From 6ed2ddf76da3f3e4a13c60c1c5278eae7bdb0ca2 Mon Sep 17 00:00:00 2001 From: figure-0e <133478007+figure-0e@users.noreply.github.com> Date: Tue, 1 Aug 2023 02:40:42 -0600 Subject: [PATCH 01/11] Correct logic to meet join-lemmy requirement, don't have closed signups. Allows Open and Applications. (#3761) Co-authored-by: Josh Bernardini --- crates/routes/src/nodeinfo.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/routes/src/nodeinfo.rs b/crates/routes/src/nodeinfo.rs index f9df94122..736ab4e04 100644 --- a/crates/routes/src/nodeinfo.rs +++ b/crates/routes/src/nodeinfo.rs @@ -48,7 +48,9 @@ async fn node_info(context: web::Data) -> Result Date: Tue, 1 Aug 2023 10:55:28 +0200 Subject: [PATCH 02/11] Fix fetch instance software version from nodeinfo (#3772) Fixes #3771 --- src/scheduled_tasks.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index c44d61f27..28315beaa 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -387,12 +387,13 @@ fn update_instance_software(conn: &mut PgConnection, user_agent: &str) -> LemmyR Ok(res) => match res.json::() { Ok(node_info) => { // Instance sent valid nodeinfo, write it to db + let software = node_info.software.as_ref(); Some( InstanceForm::builder() .domain(instance.domain) .updated(Some(naive_now())) - .software(node_info.software.and_then(|s| s.name)) - .version(node_info.version.clone()) + .software(software.and_then(|s| s.name.clone())) + .version(software.and_then(|s| s.version.clone())) .build(), ) } From 05a7fced65108cffd208b0891706f56a8febd5d5 Mon Sep 17 00:00:00 2001 From: RocketDerp <113625597+RocketDerp@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:14:40 -0700 Subject: [PATCH 03/11] Enhanced testing of comments. Validate reply notifications, mentions (#3686) * shared.ts first test of getReplies * comment testing now validates reply notifications and mentions, some code comment cleanup in other functions * comments revised * first use of getUnreadCount in testing * test notification of new comment replies, clarify usage of getReplies * killall moved earlier in bash script * api-test jest run does not need directory prefix, make consistent with other jest runs * do not put my testing system password into script * fix, killall exits script when no process found * killall now moved to parent script to release locks before database create * need to run killall a second time, before database drop * first use of getReplies getPosts saveUserSettings * accidental duplication of functions, removed * try to sync shared library with main * Nutomic feedback: Better to rename the var instead of putting a comment which can easily get outdated. * Correct logic to meet join-lemmy requirement, don't have closed signups. Allows Open and Applications. (#3761) Co-authored-by: Josh Bernardini * Fix fetch instance software version from nodeinfo (#3772) Fixes #3771 * remove unused code, revert killall change --------- Co-authored-by: Dessalines Co-authored-by: figure-0e <133478007+figure-0e@users.noreply.github.com> Co-authored-by: Josh Bernardini Co-authored-by: Denis Dzyubenko Co-authored-by: Felix Ableitner --- api_tests/package.json | 2 +- api_tests/prepare-drone-federation-test.sh | 2 +- api_tests/run-federation-test.sh | 2 - api_tests/src/comment.spec.ts | 119 +++++++++++++++------ api_tests/src/shared.ts | 27 ++++- 5 files changed, 114 insertions(+), 38 deletions(-) diff --git a/api_tests/package.json b/api_tests/package.json index ec692e1b5..1810b8d2f 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -9,7 +9,7 @@ "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'", "fix": "prettier --write src && eslint --fix src", - "api-test": "jest -i follow.spec.ts && jest -i src/post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts" + "api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts" }, "devDependencies": { "@types/jest": "^29.5.1", diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index 7eceeeb77..3aae16bda 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -31,7 +31,7 @@ else fi echo "killall existing lemmy_server processes" -killall lemmy_server || true +killall -s1 lemmy_server || true echo "$PWD" diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index 0d241e2ab..f611cce65 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -13,8 +13,6 @@ popd yarn yarn api-test || true -killall -s1 lemmy_server - for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE" done diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index d7d533119..246497617 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -30,10 +30,12 @@ import { getCommentParentId, resolveCommunity, getPersonDetails, + getReplies, + getUnreadCount, } from "./shared"; import { CommentView } from "lemmy-js-client/dist/types/CommentView"; -let postRes: PostResponse; +let postOnAlphaRes: PostResponse; beforeAll(async () => { await setupLogins(); @@ -42,7 +44,7 @@ beforeAll(async () => { await followBeta(gamma); let betaCommunity = (await resolveBetaCommunity(alpha)).community; if (betaCommunity) { - postRes = await createPost(alpha, betaCommunity.community.id); + postOnAlphaRes = await createPost(alpha, betaCommunity.community.id); } }); @@ -65,7 +67,7 @@ function assertCommentFederation( } test("Create a comment", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); expect(commentRes.comment_view.comment.content).toBeDefined(); expect(commentRes.comment_view.community.local).toBe(false); expect(commentRes.comment_view.creator.local).toBe(true); @@ -87,7 +89,7 @@ test("Create a comment in a non-existent post", async () => { }); test("Update a comment", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Federate the comment first let betaComment = ( await resolveComment(beta, commentRes.comment_view.comment) @@ -113,7 +115,7 @@ test("Update a comment", async () => { test("Delete a comment", async () => { // creating a comment on alpha (remote from home of community) - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Find the comment on beta (home of community) let betaComment = ( @@ -167,7 +169,7 @@ test("Delete a comment", async () => { }); test.skip("Remove a comment from admin and community on the same instance", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Get the id for beta let betaCommentId = ( @@ -189,13 +191,14 @@ test.skip("Remove a comment from admin and community on the same instance", asyn ); expect(refetchedPostComments.comments[0].comment.removed).toBe(true); + // beta will unremove the comment let unremoveCommentRes = await removeComment(beta, false, betaCommentId); expect(unremoveCommentRes.comment_view.comment.removed).toBe(false); - // Make sure that comment is unremoved on beta + // Make sure that comment is unremoved on alpha let refetchedPostComments2 = await getComments( alpha, - postRes.post_view.post.id, + postOnAlphaRes.post_view.post.id, ); expect(refetchedPostComments2.comments[0].comment.removed).toBe(false); assertCommentFederation( @@ -249,7 +252,7 @@ test("Remove a comment from admin and community on different instance", async () }); test("Unlike a comment", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Lemmy automatically creates 1 like (vote) by author of comment. // Make sure that comment is liked (voted up) on gamma, downstream peer @@ -286,7 +289,7 @@ test("Unlike a comment", async () => { }); test("Federated comment like", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); // Find the comment on beta let betaComment = ( @@ -301,13 +304,14 @@ test("Federated comment like", async () => { expect(like.comment_view.counts.score).toBe(2); // Get the post from alpha, check the likes - let postComments = await getComments(alpha, postRes.post_view.post.id); + let postComments = await getComments(alpha, postOnAlphaRes.post_view.post.id); expect(postComments.comments[0].counts.score).toBe(2); }); -test("Reply to a comment", async () => { - // Create a comment on alpha, find it on beta - let commentRes = await createComment(alpha, postRes.post_view.post.id); +test("Reply to a comment from another instance, get notification", async () => { + // Create a root-level trunk-branch comment on alpha + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); + // find that comment id on beta let betaComment = ( await resolveComment(beta, commentRes.comment_view.comment) ).comment; @@ -316,9 +320,7 @@ test("Reply to a comment", async () => { throw "Missing beta comment"; } - // find that comment id on beta - - // Reply from beta + // Reply from beta, extending the branch let replyRes = await createComment( beta, betaComment.post.id, @@ -332,11 +334,13 @@ test("Reply to a comment", async () => { ); expect(replyRes.comment_view.counts.score).toBe(1); - // Make sure that comment is seen on alpha + // 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 postComments = await getComments(alpha, postRes.post_view.post.id); + let postComments = await getComments(alpha, postOnAlphaRes.post_view.post.id); + // Note: in Lemmy 0.18.3 pre-release this is coming up 7 + expect(postComments.comments.length).toBeGreaterThanOrEqual(2); let alphaComment = postComments.comments[0]; expect(alphaComment.comment.content).toBeDefined(); expect(getCommentParentId(alphaComment.comment)).toBe( @@ -346,15 +350,33 @@ test("Reply to a comment", async () => { expect(alphaComment.creator.local).toBe(false); expect(alphaComment.counts.score).toBe(1); assertCommentFederation(alphaComment, replyRes.comment_view); + + // Did alpha get notified of the reply from beta? + let alphaUnreadCountRes = await getUnreadCount(alpha); + expect(alphaUnreadCountRes.replies).toBe(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); + // 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); + // 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); }); -test("Mention beta", async () => { - // Create a mention on alpha +test("Mention beta from alpha", async () => { + // 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 let mentionContent = "A test mention of @lemmy_beta@lemmy-beta:8551"; - let commentRes = await createComment(alpha, postRes.post_view.post.id); let mentionRes = await createComment( alpha, - postRes.post_view.post.id, + postOnAlphaRes.post_view.post.id, commentRes.comment_view.comment.id, mentionContent, ); @@ -363,15 +385,44 @@ test("Mention beta", async () => { expect(mentionRes.comment_view.creator.local).toBe(true); 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; + if (!betaPost) { + throw "unable to locate post on beta"; + } + expect(betaPost.post.ap_id).toBe(postOnAlphaRes.post_view.post.ap_id); + expect(betaPost.post.name).toBe(postOnAlphaRes.post_view.post.name); + + // Make sure that both new comments are seen on beta and have parent/child relationship + let betaPostComments = await getComments(beta, betaPost.post.id); + expect(betaPostComments.comments.length).toBeGreaterThanOrEqual(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 + expect(getCommentParentId(betaRootComment.comment)).toBeUndefined(); + expect(betaRootComment.comment.content).toBeDefined(); + // the mention reply comment should have parent that points to the branch root level comment + expect(getCommentParentId(betaPostComments.comments[0].comment)).toBe( + betaPostComments.comments[1].comment.id, + ); + expect(betaRootComment.community.local).toBe(true); + expect(betaRootComment.creator.local).toBe(false); + expect(betaRootComment.counts.score).toBe(1); + assertCommentFederation(betaRootComment, commentRes.comment_view); + let mentionsRes = await getMentions(beta); expect(mentionsRes.mentions[0].comment.content).toBeDefined(); expect(mentionsRes.mentions[0].community.local).toBe(true); expect(mentionsRes.mentions[0].creator.local).toBe(false); expect(mentionsRes.mentions[0].counts.score).toBe(1); + // the reply comment with mention should be the most fresh, newest, index 0 + expect(mentionsRes.mentions[0].person_mention.comment_id).toBe( + betaPostComments.comments[0].comment.id, + ); }); test("Comment Search", async () => { - let commentRes = await createComment(alpha, postRes.post_view.post.id); + let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id); let betaComment = ( await resolveComment(beta, commentRes.comment_view.comment) ).comment; @@ -496,13 +547,13 @@ test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde ).toBe(0); // B creates a post, and two comments, should be invisible to A - let postRes = await createPost(beta, 2); - expect(postRes.post_view.post.name).toBeDefined(); + let postOnBetaRes = await createPost(beta, 2); + expect(postOnBetaRes.post_view.post.name).toBeDefined(); let parentCommentContent = "An invisible top level comment from beta"; let parentCommentRes = await createComment( beta, - postRes.post_view.post.id, + postOnBetaRes.post_view.post.id, undefined, parentCommentContent, ); @@ -514,7 +565,7 @@ test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde let childCommentContent = "An invisible child comment from beta"; let childCommentRes = await createComment( beta, - postRes.post_view.post.id, + postOnBetaRes.post_view.post.id, parentCommentRes.comment_view.comment.id, childCommentContent, ); @@ -537,7 +588,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, postRes.post_view.post)).post; + let alphaPostB = (await resolvePost(alpha, postOnBetaRes.post_view.post)) + .post; if (!alphaPostB) { throw "Missing alpha post B"; } @@ -564,10 +616,11 @@ test("Report a comment", async () => { if (!betaCommunity) { throw "Missing beta community"; } - let postRes = (await createPost(beta, betaCommunity.community.id)).post_view - .post; - expect(postRes).toBeDefined(); - let commentRes = (await createComment(beta, postRes.id)).comment_view.comment; + let postOnBetaRes = (await createPost(beta, betaCommunity.community.id)) + .post_view.post; + expect(postOnBetaRes).toBeDefined(); + let commentRes = (await createComment(beta, postOnBetaRes.id)).comment_view + .comment; expect(commentRes).toBeDefined(); let alphaComment = (await resolveComment(alpha, commentRes)).comment?.comment; diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index f873e78c1..9460d896a 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -1,4 +1,11 @@ -import { LemmyHttp } from "lemmy-js-client"; +import { + GetReplies, + GetRepliesResponse, + GetUnreadCount, + GetUnreadCountResponse, + LemmyHttp, + LocalUser, +} from "lemmy-js-client"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; import { DeletePost } from "lemmy-js-client/dist/types/DeletePost"; import { EditPost } from "lemmy-js-client/dist/types/EditPost"; @@ -325,6 +332,24 @@ export async function getComments( return api.client.getComments(form); } +export async function getUnreadCount( + api: API, +): Promise { + let form: GetUnreadCount = { + auth: api.auth, + }; + return api.client.getUnreadCount(form); +} + +export async function getReplies(api: API): Promise { + let form: GetReplies = { + sort: "New", + unread_only: false, + auth: api.auth, + }; + return api.client.getReplies(form); +} + export async function resolveComment( api: API, comment: Comment, From d82194cfe9f98984a64353f6511bb73b4f08baa4 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 1 Aug 2023 15:53:36 +0200 Subject: [PATCH 04/11] Rewrite some federation actions to remove Perform/SendActivity (ref #3670) (#3758) --- crates/api/src/comment/like.rs | 111 +++++++------ crates/api/src/post/like.rs | 97 +++++++----- crates/api/src/post/mod.rs | 12 +- crates/api_common/src/send_activity.rs | 10 +- crates/api_crud/src/comment/create.rs | 3 +- crates/api_crud/src/comment/delete.rs | 110 +++++++------ crates/api_crud/src/comment/read.rs | 3 +- crates/api_crud/src/comment/remove.rs | 125 ++++++++------- crates/api_crud/src/comment/update.rs | 129 +++++++-------- crates/api_crud/src/post/update.rs | 147 +++++++++--------- .../activities/create_or_update/comment.rs | 21 --- .../src/activities/create_or_update/post.rs | 25 +-- crates/apub/src/activities/deletion/mod.rs | 47 +----- crates/apub/src/activities/mod.rs | 23 ++- crates/apub/src/activities/voting/mod.rs | 89 ++--------- src/api_routes_http.rs | 29 ++-- 16 files changed, 460 insertions(+), 521 deletions(-) diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index e84c55cbf..13122b4be 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -1,9 +1,10 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_comment_response, comment::{CommentResponse, CreateCommentLike}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, check_downvotes_enabled, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -17,70 +18,80 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl Perform for CreateCommentLike { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn like_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_site = LocalSite::read(&mut context.pool()).await?; + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreateCommentLike = self; - 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(); - let mut recipient_ids = Vec::::new(); + // Don't do a downvote if site has downvotes disabled + check_downvotes_enabled(data.score, &local_site)?; - // Don't do a downvote if site has downvotes disabled - check_downvotes_enabled(data.score, &local_site)?; + let comment_id = data.comment_id; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; - let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + check_community_ban( + local_user_view.person.id, + orig_comment.community.id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_comment.community.id, - &mut context.pool(), - ) - .await?; - - // Add parent poster or commenter to recipients - let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await; - if let Ok(reply) = comment_reply { - let recipient_id = reply.recipient_id; - if let Ok(local_recipient) = - LocalUserView::read_person(&mut context.pool(), recipient_id).await - { - recipient_ids.push(local_recipient.local_user.id); - } + // Add parent poster or commenter to recipients + let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await; + if let Ok(reply) = comment_reply { + let recipient_id = reply.recipient_id; + if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await + { + recipient_ids.push(local_recipient.local_user.id); } + } - let like_form = CommentLikeForm { - comment_id: data.comment_id, - post_id: orig_comment.post.id, - person_id: local_user_view.person.id, - score: data.score, - }; + let like_form = CommentLikeForm { + comment_id: data.comment_id, + post_id: orig_comment.post.id, + person_id: local_user_view.person.id, + score: data.score, + }; - // Remove any likes first - let person_id = local_user_view.person.id; + // Remove any likes first + let person_id = local_user_view.person.id; - CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; + CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; - // Only add the like if the score isnt 0 - let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1); - if do_add { - CommentLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; - } + // Only add the like if the score isnt 0 + let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1); + if do_add { + CommentLike::like(&mut context.pool(), &like_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; + } + ActivityChannel::submit_activity( + SendActivityData::LikePostOrComment( + orig_comment.comment.ap_id, + local_user_view.person.clone(), + orig_comment.community, + data.score, + ), + &context, + ) + .await?; + + Ok(Json( build_comment_response( - context, + context.deref(), comment_id, Some(local_user_view), None, recipient_ids, ) - .await - } + .await?, + )) } diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index 025129d31..1ff119f03 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -1,9 +1,10 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{CreatePostLike, PostResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, check_community_deleted_or_removed, @@ -14,66 +15,78 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ source::{ + community::Community, local_site::LocalSite, post::{Post, PostLike, PostLikeForm}, }, traits::{Crud, Likeable}, }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl Perform for CreatePostLike { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn like_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreatePostLike = self; - 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 + check_downvotes_enabled(data.score, &local_site)?; - // Don't do a downvote if site has downvotes disabled - check_downvotes_enabled(data.score, &local_site)?; + // Check for a community ban + let post_id = data.post_id; + let post = Post::read(&mut context.pool(), post_id).await?; - // Check for a community ban - let post_id = data.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; + check_community_ban( + local_user_view.person.id, + post.community_id, + &mut context.pool(), + ) + .await?; + check_community_deleted_or_removed(post.community_id, &mut context.pool()).await?; - check_community_ban( - local_user_view.person.id, - post.community_id, - &mut context.pool(), - ) - .await?; - check_community_deleted_or_removed(post.community_id, &mut context.pool()).await?; + let like_form = PostLikeForm { + post_id: data.post_id, + person_id: local_user_view.person.id, + score: data.score, + }; - let like_form = PostLikeForm { - post_id: data.post_id, - person_id: local_user_view.person.id, - score: data.score, - }; + // Remove any likes first + let person_id = local_user_view.person.id; - // Remove any likes first - let person_id = local_user_view.person.id; + PostLike::remove(&mut context.pool(), person_id, post_id).await?; - PostLike::remove(&mut context.pool(), person_id, post_id).await?; + // Only add the like if the score isnt 0 + let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1); + if do_add { + PostLike::like(&mut context.pool(), &like_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; + } - // Only add the like if the score isnt 0 - let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1); - if do_add { - PostLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; - } + // Mark the post as read + mark_post_as_read(person_id, post_id, &mut context.pool()).await?; - // Mark the post as read - mark_post_as_read(person_id, post_id, &mut context.pool()).await?; + ActivityChannel::submit_activity( + SendActivityData::LikePostOrComment( + post.ap_id, + local_user_view.person.clone(), + Community::read(&mut context.pool(), post.community_id).await?, + data.score, + ), + &context, + ) + .await?; + Ok(Json( build_post_response( - context, + context.deref(), post.community_id, local_user_view.person.id, post_id, ) - .await - } + .await?, + )) } diff --git a/crates/api/src/post/mod.rs b/crates/api/src/post/mod.rs index 4d8251356..a3b84134f 100644 --- a/crates/api/src/post/mod.rs +++ b/crates/api/src/post/mod.rs @@ -1,6 +1,6 @@ -mod feature; -mod get_link_metadata; -mod like; -mod lock; -mod mark_read; -mod save; +pub mod feature; +pub mod get_link_metadata; +pub mod like; +pub mod lock; +pub mod mark_read; +pub mod save; diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 994aea2a7..7954db284 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -1,7 +1,10 @@ use crate::context::LemmyContext; use activitypub_federation::config::Data; use futures::future::BoxFuture; -use lemmy_db_schema::source::{comment::Comment, post::Post}; +use lemmy_db_schema::{ + newtypes::DbUrl, + source::{comment::Comment, community::Community, person::Person, post::Post}, +}; use lemmy_utils::{error::LemmyResult, SYNCHRONOUS_FEDERATION}; use once_cell::sync::{Lazy, OnceCell}; use tokio::{ @@ -22,7 +25,12 @@ pub static MATCH_OUTGOING_ACTIVITIES: OnceCell = O #[derive(Debug)] pub enum SendActivityData { CreatePost(Post), + UpdatePost(Post), CreateComment(Comment), + DeleteComment(Comment, Person, Community), + RemoveComment(Comment, Person, Community, Option), + UpdateComment(Comment), + LikePostOrComment(DbUrl, Person, Community, i16), } // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index f334efe5e..8b8afc8f1 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -36,7 +36,6 @@ use lemmy_utils::{ validation::is_valid_body_field, }, }; -use std::ops::Deref; const MAX_COMMENT_DEPTH_LIMIT: usize = 100; @@ -196,7 +195,7 @@ pub async fn create_comment( Ok(Json( build_comment_response( - context.deref(), + &context, inserted_comment.id, Some(local_user_view), data.form_id.clone(), diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index eba7d1dec..10063c66f 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::{build_comment_response, send_local_notifs}, comment::{CommentResponse, DeleteComment}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -15,66 +16,75 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeleteComment { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &DeleteComment = self; - 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?; - let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + // Dont delete it if its already been deleted. + if orig_comment.comment.deleted == data.deleted { + return Err(LemmyErrorType::CouldntUpdateComment)?; + } - // Dont delete it if its already been deleted. - if orig_comment.comment.deleted == data.deleted { - return Err(LemmyErrorType::CouldntUpdateComment)?; - } + check_community_ban( + local_user_view.person.id, + orig_comment.community.id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_comment.community.id, - &mut context.pool(), - ) - .await?; + // Verify that only the creator can delete + if local_user_view.person.id != orig_comment.creator.id { + return Err(LemmyErrorType::NoCommentEditAllowed)?; + } - // Verify that only the creator can delete - if local_user_view.person.id != orig_comment.creator.id { - return Err(LemmyErrorType::NoCommentEditAllowed)?; - } + // Do the delete + let deleted = data.deleted; + let updated_comment = Comment::update( + &mut context.pool(), + comment_id, + &CommentUpdateForm::builder().deleted(Some(deleted)).build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - // Do the delete - let deleted = data.deleted; - let updated_comment = Comment::update( - &mut context.pool(), - comment_id, - &CommentUpdateForm::builder().deleted(Some(deleted)).build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + let post_id = updated_comment.post_id; + let post = Post::read(&mut context.pool(), post_id).await?; + let recipient_ids = send_local_notifs( + vec![], + &updated_comment, + &local_user_view.person, + &post, + false, + &context, + ) + .await?; + let updated_comment_id = updated_comment.id; - let post_id = updated_comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; - let recipient_ids = send_local_notifs( - vec![], - &updated_comment, - &local_user_view.person, - &post, - false, - context, - ) - .await?; + ActivityChannel::submit_activity( + SendActivityData::DeleteComment( + updated_comment, + local_user_view.person.clone(), + orig_comment.community, + ), + &context, + ) + .await?; + Ok(Json( build_comment_response( - context.deref(), - updated_comment.id, + &context, + updated_comment_id, Some(local_user_view), None, recipient_ids, ) - .await - } + .await?, + )) } diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index 1a794dc5d..4ade60df5 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -7,7 +7,6 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_utils::error::LemmyError; -use std::ops::Deref; #[tracing::instrument(skip(context))] pub async fn get_comment( @@ -20,6 +19,6 @@ pub async fn get_comment( check_private_instance(&local_user_view, &local_site)?; Ok(Json( - build_comment_response(context.deref(), data.id, local_user_view, None, vec![]).await?, + build_comment_response(&context, data.id, local_user_view, None, vec![]).await?, )) } diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index cfc3ccff7..b20712986 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::{build_comment_response, send_local_notifs}, comment::{CommentResponse, RemoveComment}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -16,73 +17,83 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl PerformCrud for RemoveComment { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn remove_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &RemoveComment = self; - 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?; - let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + check_community_ban( + local_user_view.person.id, + orig_comment.community.id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_comment.community.id, - &mut context.pool(), - ) - .await?; + // Verify that only a mod or admin can remove + is_mod_or_admin( + &mut context.pool(), + local_user_view.person.id, + orig_comment.community.id, + ) + .await?; - // Verify that only a mod or admin can remove - is_mod_or_admin( - &mut context.pool(), - local_user_view.person.id, - orig_comment.community.id, - ) - .await?; + // Do the remove + let removed = data.removed; + let updated_comment = Comment::update( + &mut context.pool(), + comment_id, + &CommentUpdateForm::builder().removed(Some(removed)).build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - // Do the remove - let removed = data.removed; - let updated_comment = Comment::update( - &mut context.pool(), - comment_id, - &CommentUpdateForm::builder().removed(Some(removed)).build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + // Mod tables + let form = ModRemoveCommentForm { + mod_person_id: local_user_view.person.id, + comment_id: data.comment_id, + removed: Some(removed), + reason: data.reason.clone(), + }; + ModRemoveComment::create(&mut context.pool(), &form).await?; - // Mod tables - let form = ModRemoveCommentForm { - mod_person_id: local_user_view.person.id, - comment_id: data.comment_id, - removed: Some(removed), - reason: data.reason.clone(), - }; - ModRemoveComment::create(&mut context.pool(), &form).await?; + let post_id = updated_comment.post_id; + let post = Post::read(&mut context.pool(), post_id).await?; + let recipient_ids = send_local_notifs( + vec![], + &updated_comment, + &local_user_view.person.clone(), + &post, + false, + &context, + ) + .await?; + let updated_comment_id = updated_comment.id; - let post_id = updated_comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; - let recipient_ids = send_local_notifs( - vec![], - &updated_comment, - &local_user_view.person.clone(), - &post, - false, - context, - ) - .await?; + ActivityChannel::submit_activity( + SendActivityData::RemoveComment( + updated_comment, + local_user_view.person.clone(), + orig_comment.community, + data.reason.clone(), + ), + &context, + ) + .await?; + Ok(Json( build_comment_response( - context.deref(), - updated_comment.id, + &context, + updated_comment_id, Some(local_user_view), None, recipient_ids, ) - .await - } + .await?, + )) } diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 5d4d75a37..c7b82ba97 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::{build_comment_response, send_local_notifs}, comment::{CommentResponse, EditComment}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, local_site_to_slur_regex, @@ -29,79 +30,83 @@ use lemmy_utils::{ validation::is_valid_body_field, }, }; -use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditComment { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn update_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &EditComment = self; - 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; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; - let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + check_community_ban( + local_user_view.person.id, + orig_comment.community.id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_comment.community.id, - &mut context.pool(), - ) - .await?; + // Verify that only the creator can edit + if local_user_view.person.id != orig_comment.creator.id { + return Err(LemmyErrorType::NoCommentEditAllowed)?; + } - // Verify that only the creator can edit - if local_user_view.person.id != orig_comment.creator.id { - return Err(LemmyErrorType::NoCommentEditAllowed)?; - } + let language_id = data.language_id; + CommunityLanguage::is_allowed_community_language( + &mut context.pool(), + language_id, + orig_comment.community.id, + ) + .await?; - let language_id = self.language_id; - CommunityLanguage::is_allowed_community_language( - &mut context.pool(), - language_id, - orig_comment.community.id, - ) - .await?; + // Update the Content + let content = data + .content + .as_ref() + .map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site))); + is_valid_body_field(&content, false)?; + let content = sanitize_html_opt(&content); - // Update the Content - let content = data - .content - .as_ref() - .map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site))); - is_valid_body_field(&content, false)?; - let content = sanitize_html_opt(&content); + let comment_id = data.comment_id; + let form = CommentUpdateForm::builder() + .content(content) + .language_id(data.language_id) + .updated(Some(Some(naive_now()))) + .build(); + let updated_comment = Comment::update(&mut context.pool(), comment_id, &form) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - let comment_id = data.comment_id; - let form = CommentUpdateForm::builder() - .content(content) - .language_id(data.language_id) - .updated(Some(Some(naive_now()))) - .build(); - let updated_comment = Comment::update(&mut context.pool(), comment_id, &form) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + // Do the mentions / recipients + let updated_comment_content = updated_comment.content.clone(); + let mentions = scrape_text_for_mentions(&updated_comment_content); + let recipient_ids = send_local_notifs( + mentions, + &updated_comment, + &local_user_view.person, + &orig_comment.post, + false, + &context, + ) + .await?; - // Do the mentions / recipients - let updated_comment_content = updated_comment.content.clone(); - let mentions = scrape_text_for_mentions(&updated_comment_content); - let recipient_ids = send_local_notifs( - mentions, - &updated_comment, - &local_user_view.person, - &orig_comment.post, - false, - context, - ) - .await?; + ActivityChannel::submit_activity( + SendActivityData::UpdateComment(updated_comment.clone()), + &context, + ) + .await?; + Ok(Json( build_comment_response( - context.deref(), + &context, updated_comment.id, Some(local_user_view), - self.form_id.clone(), + data.form_id.clone(), recipient_ids, ) - .await - } + .await?, + )) } diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index f3be5f6af..3341392bc 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -1,10 +1,11 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{EditPost, PostResponse}, request::fetch_site_data, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, local_site_to_slur_regex, @@ -28,95 +29,97 @@ use lemmy_utils::{ validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title}, }, }; +use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditPost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn update_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &EditPost = self; - 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(); - let data_url = data.url.as_ref(); + // TODO No good way to handle a clear. + // Issue link: https://github.com/LemmyNet/lemmy/issues/2287 + let url = Some(data_url.map(clean_url_params).map(Into::into)); - // TODO No good way to handle a clear. - // Issue link: https://github.com/LemmyNet/lemmy/issues/2287 - let url = Some(data_url.map(clean_url_params).map(Into::into)); + let slur_regex = local_site_to_slur_regex(&local_site); + check_slurs_opt(&data.name, &slur_regex)?; + check_slurs_opt(&data.body, &slur_regex)?; - let slur_regex = local_site_to_slur_regex(&local_site); - check_slurs_opt(&data.name, &slur_regex)?; - check_slurs_opt(&data.body, &slur_regex)?; + if let Some(name) = &data.name { + is_valid_post_title(name)?; + } - if let Some(name) = &data.name { - is_valid_post_title(name)?; - } + is_valid_body_field(&data.body, true)?; + check_url_scheme(&data.url)?; - is_valid_body_field(&data.body, true)?; - check_url_scheme(&data.url)?; + let post_id = data.post_id; + let orig_post = Post::read(&mut context.pool(), post_id).await?; - let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + check_community_ban( + local_user_view.person.id, + orig_post.community_id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_post.community_id, - &mut context.pool(), - ) - .await?; + // Verify that only the creator can edit + if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { + return Err(LemmyErrorType::NoPostEditAllowed)?; + } - // Verify that only the creator can edit - if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(LemmyErrorType::NoPostEditAllowed)?; - } + // Fetch post links and Pictrs cached image + let data_url = data.url.as_ref(); + let (metadata_res, thumbnail_url) = + fetch_site_data(context.client(), context.settings(), data_url, true).await; + let (embed_title, embed_description, embed_video_url) = metadata_res + .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url))) + .unwrap_or_default(); - // Fetch post links and Pictrs cached image - let data_url = data.url.as_ref(); - let (metadata_res, thumbnail_url) = - fetch_site_data(context.client(), context.settings(), data_url, true).await; - let (embed_title, embed_description, embed_video_url) = metadata_res - .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url))) - .unwrap_or_default(); + let name = sanitize_html_opt(&data.name); + let body = sanitize_html_opt(&data.body); + let body = diesel_option_overwrite(body); + let embed_title = embed_title.map(|e| sanitize_html_opt(&e)); + let embed_description = embed_description.map(|e| sanitize_html_opt(&e)); - let name = sanitize_html_opt(&data.name); - let body = sanitize_html_opt(&data.body); - let body = diesel_option_overwrite(body); - let embed_title = embed_title.map(|e| sanitize_html_opt(&e)); - let embed_description = embed_description.map(|e| sanitize_html_opt(&e)); + let language_id = data.language_id; + CommunityLanguage::is_allowed_community_language( + &mut context.pool(), + language_id, + orig_post.community_id, + ) + .await?; - let language_id = self.language_id; - CommunityLanguage::is_allowed_community_language( - &mut context.pool(), - language_id, - orig_post.community_id, - ) - .await?; + let post_form = PostUpdateForm::builder() + .name(name) + .url(url) + .body(body) + .nsfw(data.nsfw) + .embed_title(embed_title) + .embed_description(embed_description) + .embed_video_url(embed_video_url) + .language_id(data.language_id) + .thumbnail_url(Some(thumbnail_url)) + .updated(Some(Some(naive_now()))) + .build(); - let post_form = PostUpdateForm::builder() - .name(name) - .url(url) - .body(body) - .nsfw(data.nsfw) - .embed_title(embed_title) - .embed_description(embed_description) - .embed_video_url(embed_video_url) - .language_id(data.language_id) - .thumbnail_url(Some(thumbnail_url)) - .updated(Some(Some(naive_now()))) - .build(); + let post_id = data.post_id; + let updated_post = Post::update(&mut context.pool(), post_id, &post_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?; - let post_id = data.post_id; - Post::update(&mut context.pool(), post_id, &post_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?; + ActivityChannel::submit_activity(SendActivityData::UpdatePost(updated_post), &context).await?; + Ok(Json( build_post_response( - context, + context.deref(), orig_post.community_id, local_user_view.person.id, post_id, ) - .await - } + .await?, + )) } diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index fa235a7f2..d54ca309e 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -14,7 +14,6 @@ use crate::{ activities::{create_or_update::note::CreateOrUpdateNote, CreateOrUpdateType}, InCommunity, }, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -25,7 +24,6 @@ use activitypub_federation::{ }; use lemmy_api_common::{ build_response::send_local_notifs, - comment::{CommentResponse, EditComment}, context::LemmyContext, utils::{check_post_deleted_or_removed, is_mod_or_admin}, }; @@ -43,25 +41,6 @@ use lemmy_db_schema::{ use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions}; use url::Url; -#[async_trait::async_trait] -impl SendActivity for EditComment { - type Response = CommentResponse; - - async fn send_activity( - _request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - CreateOrUpdateNote::send( - response.comment_view.comment.clone(), - response.comment_view.creator.id, - CreateOrUpdateType::Update, - context.reset_request_count(), - ) - .await - } -} - impl CreateOrUpdateNote { #[tracing::instrument(skip(comment, person_id, kind, context))] pub(crate) async fn send( diff --git a/crates/apub/src/activities/create_or_update/post.rs b/crates/apub/src/activities/create_or_update/post.rs index 4767114f9..a9ac79364 100644 --- a/crates/apub/src/activities/create_or_update/post.rs +++ b/crates/apub/src/activities/create_or_update/post.rs @@ -14,7 +14,6 @@ use crate::{ activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType}, InCommunity, }, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -22,10 +21,7 @@ use activitypub_federation::{ protocol::verification::{verify_domains_match, verify_urls_match}, traits::{ActivityHandler, Actor, Object}, }; -use lemmy_api_common::{ - context::LemmyContext, - post::{EditPost, PostResponse}, -}; +use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ aggregates::structs::PostAggregates, newtypes::PersonId, @@ -39,25 +35,6 @@ use lemmy_db_schema::{ use lemmy_utils::error::{LemmyError, LemmyErrorType}; use url::Url; -#[async_trait::async_trait] -impl SendActivity for EditPost { - type Response = PostResponse; - - async fn send_activity( - _request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - CreateOrUpdatePage::send( - response.post_view.post.clone(), - response.post_view.creator.id, - CreateOrUpdateType::Update, - context.reset_request_count(), - ) - .await - } -} - impl CreateOrUpdatePage { pub(crate) async fn new( post: ApubPost, diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index 3b8c8b537..c571ac22b 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -29,7 +29,6 @@ use activitypub_federation::{ traits::{Actor, Object}, }; use lemmy_api_common::{ - comment::{CommentResponse, DeleteComment, RemoveComment}, community::{CommunityResponse, DeleteCommunity, RemoveCommunity}, context::LemmyContext, post::{DeletePost, PostResponse, RemovePost}, @@ -102,50 +101,6 @@ impl SendActivity for RemovePost { } } -#[async_trait::async_trait] -impl SendActivity for DeleteComment { - type Response = CommentResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let community_id = response.comment_view.community.id; - let community = Community::read(&mut context.pool(), community_id).await?; - let person = Person::read(&mut context.pool(), response.comment_view.creator.id).await?; - let deletable = DeletableObjects::Comment(response.comment_view.comment.clone().into()); - send_apub_delete_in_community(person, community, deletable, None, request.deleted, context) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for RemoveComment { - type Response = CommentResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let comment = Comment::read(&mut context.pool(), request.comment_id).await?; - let community = - Community::read(&mut context.pool(), response.comment_view.community.id).await?; - let deletable = DeletableObjects::Comment(comment.into()); - send_apub_delete_in_community( - local_user_view.person, - community, - deletable, - request.reason.clone().or_else(|| Some(String::new())), - request.removed, - context, - ) - .await - } -} - #[async_trait::async_trait] impl SendActivity for DeletePrivateMessage { type Response = PrivateMessageResponse; @@ -217,7 +172,7 @@ impl SendActivity for RemoveCommunity { /// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this /// action was done by a normal user. #[tracing::instrument(skip_all)] -async fn send_apub_delete_in_community( +pub(crate) async fn send_apub_delete_in_community( actor: Person, community: Community, object: DeletableObjects, diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index c7d19e372..c577f8bc9 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -1,4 +1,8 @@ use crate::{ + activities::{ + deletion::{send_apub_delete_in_community, DeletableObjects}, + voting::send_like_activity, + }, objects::{community::ApubCommunity, person::ApubPerson}, protocol::activities::{ create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage}, @@ -222,15 +226,30 @@ pub async fn match_outgoing_activities( ) -> LemmyResult<()> { let context = context.reset_request_count(); let fed_task = async { + use SendActivityData::*; match data { - SendActivityData::CreatePost(post) => { + CreatePost(post) | UpdatePost(post) => { let creator_id = post.creator_id; CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Create, context).await } - SendActivityData::CreateComment(comment) => { + CreateComment(comment) | UpdateComment(comment) => { let creator_id = comment.creator_id; CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Create, context).await } + DeleteComment(comment, actor, community) => { + let is_deleted = comment.deleted; + let deletable = DeletableObjects::Comment(comment.into()); + send_apub_delete_in_community(actor, community, deletable, None, is_deleted, &context).await + } + RemoveComment(comment, actor, community, reason) => { + let is_removed = comment.removed; + let deletable = DeletableObjects::Comment(comment.into()); + send_apub_delete_in_community(actor, community, deletable, reason, is_removed, &context) + .await + } + LikePostOrComment(object_id, person, community, score) => { + send_like_activity(object_id, person, community, score, context).await + } } }; if *SYNCHRONOUS_FEDERATION { diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 24250c501..742a4407c 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -2,106 +2,51 @@ use crate::{ activities::community::send_activity_in_community, activity_lists::AnnouncableActivities, fetcher::post_or_comment::PostOrComment, - objects::{comment::ApubComment, person::ApubPerson, post::ApubPost}, + objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost}, protocol::activities::voting::{ undo_vote::UndoVote, vote::{Vote, VoteType}, }, - SendActivity, }; use activitypub_federation::{config::Data, fetch::object_id::ObjectId}; -use lemmy_api_common::{ - comment::{CommentResponse, CreateCommentLike}, - context::LemmyContext, - post::{CreatePostLike, PostResponse}, - sensitive::Sensitive, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ - newtypes::CommunityId, + newtypes::DbUrl, source::{ comment::{CommentLike, CommentLikeForm}, community::Community, person::Person, post::{PostLike, PostLikeForm}, }, - traits::{Crud, Likeable}, + traits::Likeable, }; use lemmy_utils::error::LemmyError; pub mod undo_vote; pub mod vote; -#[async_trait::async_trait] -impl SendActivity for CreatePostLike { - type Response = PostResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let object_id = ObjectId::from(response.post_view.post.ap_id.clone()); - let community_id = response.post_view.community.id; - send_activity( - object_id, - community_id, - request.score, - &request.auth, - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for CreateCommentLike { - type Response = CommentResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let object_id = ObjectId::from(response.comment_view.comment.ap_id.clone()); - let community_id = response.comment_view.community.id; - send_activity( - object_id, - community_id, - request.score, - &request.auth, - context, - ) - .await - } -} - -async fn send_activity( - object_id: ObjectId, - community_id: CommunityId, +pub(crate) async fn send_like_activity( + object_id: DbUrl, + actor: Person, + community: Community, score: i16, - jwt: &Sensitive, - context: &Data, + context: Data, ) -> Result<(), LemmyError> { - let community = Community::read(&mut context.pool(), community_id) - .await? - .into(); - let local_user_view = local_user_view_from_jwt(jwt, context).await?; - let actor = Person::read(&mut context.pool(), local_user_view.person.id) - .await? - .into(); + let object_id: ObjectId = object_id.try_into()?; + let actor: ApubPerson = actor.into(); + let community: ApubCommunity = community.into(); // score of 1 means upvote, -1 downvote, 0 undo a previous vote if score != 0 { - let vote = Vote::new(object_id, &actor, &community, score.try_into()?, context)?; + let vote = Vote::new(object_id, &actor, &community, score.try_into()?, &context)?; let activity = AnnouncableActivities::Vote(vote); - send_activity_in_community(activity, &actor, &community, vec![], false, context).await + send_activity_in_community(activity, &actor, &community, vec![], false, &context).await } else { // Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here. - let vote = Vote::new(object_id, &actor, &community, VoteType::Like, context)?; - let undo_vote = UndoVote::new(vote, &actor, &community, context)?; + let vote = Vote::new(object_id, &actor, &community, VoteType::Like, &context)?; + let undo_vote = UndoVote::new(vote, &actor, &community, &context)?; let activity = AnnouncableActivities::UndoVote(undo_vote); - send_activity_in_community(activity, &actor, &community, vec![], false, context).await + send_activity_in_community(activity, &actor, &community, vec![], false, &context).await } } diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index e372e340e..6d538e63e 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -1,12 +1,13 @@ use actix_web::{guard, web, Error, HttpResponse, Result}; use lemmy_api::{ - comment::{distinguish::distinguish_comment, save::save_comment}, + comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment}, comment_report::{list::list_comment_reports, resolve::resolve_comment_report}, local_user::notifications::mark_reply_read::mark_reply_as_read, + post::like::like_post, Perform, }; use lemmy_api_common::{ - comment::{CreateCommentLike, CreateCommentReport, DeleteComment, EditComment, RemoveComment}, + comment::CreateCommentReport, community::{ AddModToCommunity, BanFromCommunity, @@ -43,10 +44,8 @@ use lemmy_api_common::{ VerifyEmail, }, post::{ - CreatePostLike, CreatePostReport, DeletePost, - EditPost, FeaturePost, GetSiteMetadata, ListPostReports, @@ -79,9 +78,15 @@ use lemmy_api_common::{ }, }; use lemmy_api_crud::{ - comment::{create::create_comment, read::get_comment}, + comment::{ + create::create_comment, + delete::delete_comment, + read::get_comment, + remove::remove_comment, + update::update_comment, + }, community::list::list_communities, - post::{create::create_post, read::get_post}, + post::{create::create_post, read::get_post, update::update_post}, private_message::read::get_private_message, site::{create::create_site, read::get_site, update::update_site}, PerformCrud, @@ -173,7 +178,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::scope("/post") .wrap(rate_limit.message()) .route("", web::get().to(get_post)) - .route("", web::put().to(route_post_crud::)) + .route("", web::put().to(update_post)) .route("/delete", web::post().to(route_post_crud::)) .route("/remove", web::post().to(route_post_crud::)) .route( @@ -183,7 +188,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("/lock", web::post().to(route_post::)) .route("/feature", web::post().to(route_post::)) .route("/list", web::get().to(list_posts)) - .route("/like", web::post().to(route_post::)) + .route("/like", web::post().to(like_post)) .route("/save", web::put().to(route_post::)) .route("/report", web::post().to(route_post::)) .route( @@ -208,12 +213,12 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::scope("/comment") .wrap(rate_limit.message()) .route("", web::get().to(get_comment)) - .route("", web::put().to(route_post_crud::)) - .route("/delete", web::post().to(route_post_crud::)) - .route("/remove", web::post().to(route_post_crud::)) + .route("", web::put().to(update_comment)) + .route("/delete", web::post().to(delete_comment)) + .route("/remove", web::post().to(remove_comment)) .route("/mark_as_read", web::post().to(mark_reply_as_read)) .route("/distinguish", web::post().to(distinguish_comment)) - .route("/like", web::post().to(route_post::)) + .route("/like", web::post().to(like_comment)) .route("/save", web::put().to(save_comment)) .route("/list", web::get().to(list_comments)) .route("/report", web::post().to(route_post::)) From 91834d0d2183be2ba0a98385cef80c7be941fde2 Mon Sep 17 00:00:00 2001 From: dullbananas Date: Tue, 1 Aug 2023 07:34:10 -0700 Subject: [PATCH 05/11] Default imprementations for read and delete in Crud trait (#3707) * h * Start doing stuff * Default impl for Crud::read * Simplify Crud::read lifetimes * fmt * Stuff * Stuff * Successfully make default read implementation work * Restore Person::read * Clean up default Crud::read and rename 'query2 * Replace filter with find * Attempt default Crud::create * Change Crud to Crud<'a> (won't compile) * Revert "Change Crud to Crud<'a> (won't compile)" This reverts commit 7ed20f5f713600bd48c85aad0848d8dbaae56503. * Default Crud::delete * Remove Crud::delete definitions that match default * Remove commented Site::read * Insert trait * Revert "Insert trait" This reverts commit 9d780c24035d3a9fb12968d3009a28724046dc3a. * Use non-borrowed forms * Revert "Use non-borrowed forms" This reverts commit d2dd4425634b54ef105aab44f1c37cc10a32491e. * Revert "Revert "Change Crud to Crud<'a> (won't compile)"" This reverts commit 25a27165a8ef56495e9f605ac15c9924b101d1bf. * Fix lifetime for everything except Crud::delete * Fix Crud::delete * Add comment about futures * Attempt Crud::create * Attempt separate CrudBounds * Revert "Attempt separate CrudBounds" This reverts commit 1b4ca321c3d2a1d045e2f4c542c593582e9c6d80. * Try to fix Crud::create * Move lifetime parameters to associated types * Revert "Move lifetime parameters to associated types" This reverts commit af1bc858ce5e1dacddc4bbded2da7e4b7237e237. * Revert "Try to fix Crud::create" This reverts commit eec238496c38127cbf3d542b7cfd57ec55622d1f. * Revert "Revert "Attempt separate CrudBounds"" This reverts commit 1ec33ce5022c58a5ad079ed7f5c220fafe5f0a5f. * Revert "Attempt separate CrudBounds" This reverts commit 1b4ca321c3d2a1d045e2f4c542c593582e9c6d80. * Revert "Attempt Crud::create" This reverts commit 47e8071b6826f27e2a562680b4948c37dffa68cb. * Revert "Add comment about futures" This reverts commit b266b1465393995b3be51d5ba207d5249560884f. * Revert "Fix Crud::delete" This reverts commit 3abcce2eec55208993dd9c7c3e51cff83412d15a. * Revert "Fix lifetime for everything except Crud::delete" This reverts commit c1ad7a161bbc8495dbfb8b52073f35ae88519da6. * Revert "Revert "Revert "Change Crud to Crud<'a> (won't compile)""" This reverts commit 3129cd0fc302f34bc0aad59987b9d0eb1139076c. * Clean up * Update site.rs --- crates/db_schema/src/impls/comment.rs | 9 -- crates/db_schema/src/impls/comment_reply.rs | 7 -- crates/db_schema/src/impls/community.rs | 14 --- crates/db_schema/src/impls/local_user.rs | 11 +-- crates/db_schema/src/impls/moderator.rs | 85 ------------------- .../src/impls/password_reset_request.rs | 8 +- crates/db_schema/src/impls/person.rs | 7 +- crates/db_schema/src/impls/person_mention.rs | 7 -- crates/db_schema/src/impls/post.rs | 9 -- crates/db_schema/src/impls/private_message.rs | 16 ---- .../src/impls/registration_application.rs | 12 --- crates/db_schema/src/impls/site.rs | 5 -- crates/db_schema/src/traits.rs | 68 ++++++++++----- 13 files changed, 52 insertions(+), 206 deletions(-) diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index 534634326..88757cd02 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -156,15 +156,6 @@ impl Crud for Comment { type InsertForm = CommentInsertForm; type UpdateForm = CommentUpdateForm; type IdType = CommentId; - async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result { - let conn = &mut get_conn(pool).await?; - comment.find(comment_id).first::(conn).await - } - - async fn delete(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(comment.find(comment_id)).execute(conn).await - } /// This is unimplemented, use [[Comment::create]] async fn create(_pool: &mut DbPool<'_>, _comment_form: &Self::InsertForm) -> Result { diff --git a/crates/db_schema/src/impls/comment_reply.rs b/crates/db_schema/src/impls/comment_reply.rs index eeb171f58..c5b5a3c6a 100644 --- a/crates/db_schema/src/impls/comment_reply.rs +++ b/crates/db_schema/src/impls/comment_reply.rs @@ -13,13 +13,6 @@ impl Crud for CommentReply { type InsertForm = CommentReplyInsertForm; type UpdateForm = CommentReplyUpdateForm; type IdType = CommentReplyId; - async fn read(pool: &mut DbPool<'_>, comment_reply_id: CommentReplyId) -> Result { - let conn = &mut get_conn(pool).await?; - comment_reply - .find(comment_reply_id) - .first::(conn) - .await - } async fn create( pool: &mut DbPool<'_>, diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index 258e41504..2d0fcfe57 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -27,20 +27,6 @@ impl Crud for Community { type InsertForm = CommunityInsertForm; type UpdateForm = CommunityUpdateForm; type IdType = CommunityId; - async fn read(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result { - let conn = &mut get_conn(pool).await?; - community::table - .find(community_id) - .first::(conn) - .await - } - - async fn delete(pool: &mut DbPool<'_>, community_id: CommunityId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(community::table.find(community_id)) - .execute(conn) - .await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { let is_new_community = match &form.actor_id { diff --git a/crates/db_schema/src/impls/local_user.rs b/crates/db_schema/src/impls/local_user.rs index 0a72811ae..6ef3421d3 100644 --- a/crates/db_schema/src/impls/local_user.rs +++ b/crates/db_schema/src/impls/local_user.rs @@ -69,16 +69,7 @@ impl Crud for LocalUser { type InsertForm = LocalUserInsertForm; type UpdateForm = LocalUserUpdateForm; type IdType = LocalUserId; - async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result { - let conn = &mut get_conn(pool).await?; - local_user.find(local_user_id).first::(conn).await - } - async fn delete(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(local_user.find(local_user_id)) - .execute(conn) - .await - } + async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { let conn = &mut get_conn(pool).await?; let mut form_with_encrypted_password = form.clone(); diff --git a/crates/db_schema/src/impls/moderator.rs b/crates/db_schema/src/impls/moderator.rs index 12344f71c..a4c300b2a 100644 --- a/crates/db_schema/src/impls/moderator.rs +++ b/crates/db_schema/src/impls/moderator.rs @@ -42,11 +42,6 @@ impl Crud for ModRemovePost { type InsertForm = ModRemovePostForm; type UpdateForm = ModRemovePostForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_remove_post::dsl::mod_remove_post; - let conn = &mut get_conn(pool).await?; - mod_remove_post.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModRemovePostForm) -> Result { use crate::schema::mod_remove_post::dsl::mod_remove_post; @@ -76,11 +71,6 @@ impl Crud for ModLockPost { type InsertForm = ModLockPostForm; type UpdateForm = ModLockPostForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_lock_post::dsl::mod_lock_post; - let conn = &mut get_conn(pool).await?; - mod_lock_post.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModLockPostForm) -> Result { use crate::schema::mod_lock_post::dsl::mod_lock_post; @@ -110,11 +100,6 @@ impl Crud for ModFeaturePost { type InsertForm = ModFeaturePostForm; type UpdateForm = ModFeaturePostForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_feature_post::dsl::mod_feature_post; - let conn = &mut get_conn(pool).await?; - mod_feature_post.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModFeaturePostForm) -> Result { use crate::schema::mod_feature_post::dsl::mod_feature_post; @@ -144,11 +129,6 @@ impl Crud for ModRemoveComment { type InsertForm = ModRemoveCommentForm; type UpdateForm = ModRemoveCommentForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_remove_comment::dsl::mod_remove_comment; - let conn = &mut get_conn(pool).await?; - mod_remove_comment.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModRemoveCommentForm) -> Result { use crate::schema::mod_remove_comment::dsl::mod_remove_comment; @@ -178,11 +158,6 @@ impl Crud for ModRemoveCommunity { type InsertForm = ModRemoveCommunityForm; type UpdateForm = ModRemoveCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_remove_community::dsl::mod_remove_community; - let conn = &mut get_conn(pool).await?; - mod_remove_community.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModRemoveCommunityForm) -> Result { use crate::schema::mod_remove_community::dsl::mod_remove_community; @@ -212,14 +187,6 @@ impl Crud for ModBanFromCommunity { type InsertForm = ModBanFromCommunityForm; type UpdateForm = ModBanFromCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_ban_from_community::dsl::mod_ban_from_community; - let conn = &mut get_conn(pool).await?; - mod_ban_from_community - .find(from_id) - .first::(conn) - .await - } async fn create(pool: &mut DbPool<'_>, form: &ModBanFromCommunityForm) -> Result { use crate::schema::mod_ban_from_community::dsl::mod_ban_from_community; @@ -249,11 +216,6 @@ impl Crud for ModBan { type InsertForm = ModBanForm; type UpdateForm = ModBanForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_ban::dsl::mod_ban; - let conn = &mut get_conn(pool).await?; - mod_ban.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModBanForm) -> Result { use crate::schema::mod_ban::dsl::mod_ban; @@ -280,12 +242,6 @@ impl Crud for ModHideCommunity { type UpdateForm = ModHideCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_hide_community::dsl::mod_hide_community; - let conn = &mut get_conn(pool).await?; - mod_hide_community.find(from_id).first::(conn).await - } - async fn create(pool: &mut DbPool<'_>, form: &ModHideCommunityForm) -> Result { use crate::schema::mod_hide_community::dsl::mod_hide_community; let conn = &mut get_conn(pool).await?; @@ -314,11 +270,6 @@ impl Crud for ModAddCommunity { type InsertForm = ModAddCommunityForm; type UpdateForm = ModAddCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_add_community::dsl::mod_add_community; - let conn = &mut get_conn(pool).await?; - mod_add_community.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModAddCommunityForm) -> Result { use crate::schema::mod_add_community::dsl::mod_add_community; @@ -348,14 +299,6 @@ impl Crud for ModTransferCommunity { type InsertForm = ModTransferCommunityForm; type UpdateForm = ModTransferCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_transfer_community::dsl::mod_transfer_community; - let conn = &mut get_conn(pool).await?; - mod_transfer_community - .find(from_id) - .first::(conn) - .await - } async fn create(pool: &mut DbPool<'_>, form: &ModTransferCommunityForm) -> Result { use crate::schema::mod_transfer_community::dsl::mod_transfer_community; @@ -385,11 +328,6 @@ impl Crud for ModAdd { type InsertForm = ModAddForm; type UpdateForm = ModAddForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::mod_add::dsl::mod_add; - let conn = &mut get_conn(pool).await?; - mod_add.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &ModAddForm) -> Result { use crate::schema::mod_add::dsl::mod_add; @@ -415,11 +353,6 @@ impl Crud for AdminPurgePerson { type InsertForm = AdminPurgePersonForm; type UpdateForm = AdminPurgePersonForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::admin_purge_person::dsl::admin_purge_person; - let conn = &mut get_conn(pool).await?; - admin_purge_person.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { use crate::schema::admin_purge_person::dsl::admin_purge_person; @@ -449,14 +382,6 @@ impl Crud for AdminPurgeCommunity { type InsertForm = AdminPurgeCommunityForm; type UpdateForm = AdminPurgeCommunityForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::admin_purge_community::dsl::admin_purge_community; - let conn = &mut get_conn(pool).await?; - admin_purge_community - .find(from_id) - .first::(conn) - .await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { use crate::schema::admin_purge_community::dsl::admin_purge_community; @@ -486,11 +411,6 @@ impl Crud for AdminPurgePost { type InsertForm = AdminPurgePostForm; type UpdateForm = AdminPurgePostForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::admin_purge_post::dsl::admin_purge_post; - let conn = &mut get_conn(pool).await?; - admin_purge_post.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { use crate::schema::admin_purge_post::dsl::admin_purge_post; @@ -520,11 +440,6 @@ impl Crud for AdminPurgeComment { type InsertForm = AdminPurgeCommentForm; type UpdateForm = AdminPurgeCommentForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, from_id: i32) -> Result { - use crate::schema::admin_purge_comment::dsl::admin_purge_comment; - let conn = &mut get_conn(pool).await?; - admin_purge_comment.find(from_id).first::(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { use crate::schema::admin_purge_comment::dsl::admin_purge_comment; diff --git a/crates/db_schema/src/impls/password_reset_request.rs b/crates/db_schema/src/impls/password_reset_request.rs index ae4483d6e..9daaa1664 100644 --- a/crates/db_schema/src/impls/password_reset_request.rs +++ b/crates/db_schema/src/impls/password_reset_request.rs @@ -24,13 +24,7 @@ impl Crud for PasswordResetRequest { type InsertForm = PasswordResetRequestForm; type UpdateForm = PasswordResetRequestForm; type IdType = i32; - async fn read(pool: &mut DbPool<'_>, password_reset_request_id: i32) -> Result { - let conn = &mut get_conn(pool).await?; - password_reset_request - .find(password_reset_request_id) - .first::(conn) - .await - } + async fn create(pool: &mut DbPool<'_>, form: &PasswordResetRequestForm) -> Result { let conn = &mut get_conn(pool).await?; insert_into(password_reset_request) diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs index 2e086dcb6..53f4a4df0 100644 --- a/crates/db_schema/src/impls/person.rs +++ b/crates/db_schema/src/impls/person.rs @@ -27,12 +27,7 @@ impl Crud for Person { .first::(conn) .await } - async fn delete(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(person::table.find(person_id)) - .execute(conn) - .await - } + async fn create(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> Result { let conn = &mut get_conn(pool).await?; insert_into(person::table) diff --git a/crates/db_schema/src/impls/person_mention.rs b/crates/db_schema/src/impls/person_mention.rs index 27c04217e..f2441f00c 100644 --- a/crates/db_schema/src/impls/person_mention.rs +++ b/crates/db_schema/src/impls/person_mention.rs @@ -13,13 +13,6 @@ impl Crud for PersonMention { type InsertForm = PersonMentionInsertForm; type UpdateForm = PersonMentionUpdateForm; type IdType = PersonMentionId; - async fn read(pool: &mut DbPool<'_>, person_mention_id: PersonMentionId) -> Result { - let conn = &mut get_conn(pool).await?; - person_mention - .find(person_mention_id) - .first::(conn) - .await - } async fn create( pool: &mut DbPool<'_>, diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index f10d0cd27..60b8af2ce 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -38,15 +38,6 @@ impl Crud for Post { type InsertForm = PostInsertForm; type UpdateForm = PostUpdateForm; type IdType = PostId; - async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result { - let conn = &mut get_conn(pool).await?; - post.find(post_id).first::(conn).await - } - - async fn delete(pool: &mut DbPool<'_>, post_id: PostId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(post.find(post_id)).execute(conn).await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { let conn = &mut get_conn(pool).await?; diff --git a/crates/db_schema/src/impls/private_message.rs b/crates/db_schema/src/impls/private_message.rs index fb1d4b905..d422f0d23 100644 --- a/crates/db_schema/src/impls/private_message.rs +++ b/crates/db_schema/src/impls/private_message.rs @@ -15,16 +15,6 @@ impl Crud for PrivateMessage { type InsertForm = PrivateMessageInsertForm; type UpdateForm = PrivateMessageUpdateForm; type IdType = PrivateMessageId; - async fn read( - pool: &mut DbPool<'_>, - private_message_id: PrivateMessageId, - ) -> Result { - let conn = &mut get_conn(pool).await?; - private_message - .find(private_message_id) - .first::(conn) - .await - } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { let conn = &mut get_conn(pool).await?; @@ -48,12 +38,6 @@ impl Crud for PrivateMessage { .get_result::(conn) .await } - async fn delete(pool: &mut DbPool<'_>, pm_id: Self::IdType) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(private_message.find(pm_id)) - .execute(conn) - .await - } } impl PrivateMessage { diff --git a/crates/db_schema/src/impls/registration_application.rs b/crates/db_schema/src/impls/registration_application.rs index c8c622889..c4df7ba69 100644 --- a/crates/db_schema/src/impls/registration_application.rs +++ b/crates/db_schema/src/impls/registration_application.rs @@ -26,11 +26,6 @@ impl Crud for RegistrationApplication { .await } - async fn read(pool: &mut DbPool<'_>, id_: Self::IdType) -> Result { - let conn = &mut get_conn(pool).await?; - registration_application.find(id_).first::(conn).await - } - async fn update( pool: &mut DbPool<'_>, id_: Self::IdType, @@ -42,13 +37,6 @@ impl Crud for RegistrationApplication { .get_result::(conn) .await } - - async fn delete(pool: &mut DbPool<'_>, id_: Self::IdType) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(registration_application.find(id_)) - .execute(conn) - .await - } } impl RegistrationApplication { diff --git a/crates/db_schema/src/impls/site.rs b/crates/db_schema/src/impls/site.rs index 2820e9cd5..85e2b1f25 100644 --- a/crates/db_schema/src/impls/site.rs +++ b/crates/db_schema/src/impls/site.rs @@ -58,11 +58,6 @@ impl Crud for Site { .get_result::(conn) .await } - - async fn delete(pool: &mut DbPool<'_>, site_id: SiteId) -> Result { - let conn = &mut get_conn(pool).await?; - diesel::delete(site.find(site_id)).execute(conn).await - } } impl Site { diff --git a/crates/db_schema/src/traits.rs b/crates/db_schema/src/traits.rs index 0ba0cbff6..07f0b07e2 100644 --- a/crates/db_schema/src/traits.rs +++ b/crates/db_schema/src/traits.rs @@ -1,34 +1,64 @@ use crate::{ newtypes::{CommunityId, DbUrl, PersonId}, - utils::DbPool, + utils::{get_conn, DbPool}, +}; +use diesel::{ + associations::HasTable, + dsl, + query_builder::{DeleteStatement, IntoUpdateTarget}, + query_dsl::methods::{FindDsl, LimitDsl}, + result::Error, + Table, +}; +use diesel_async::{ + methods::{ExecuteDsl, LoadQuery}, + AsyncPgConnection, + RunQueryDsl, }; -use diesel::result::Error; +/// Returned by `diesel::delete` +pub type Delete = DeleteStatement<::Table, ::WhereClause>; + +/// Returned by `Self::table().find(id)` +pub type Find = dsl::Find<::Table, ::IdType>; + +pub type PrimaryKey = <::Table as Table>::PrimaryKey; + +// Trying to create default implementations for `create` and `update` results in a lifetime mess and weird compile errors. +// https://github.com/rust-lang/rust/issues/102211 #[async_trait] -pub trait Crud { +pub trait Crud: HasTable + Sized +where + Self::Table: FindDsl, + Find: LimitDsl + IntoUpdateTarget + Send, + Delete>: ExecuteDsl + Send + 'static, + + // Used by `RunQueryDsl::first` + dsl::Limit>: LoadQuery<'static, AsyncPgConnection, Self> + Send + 'static, +{ type InsertForm; type UpdateForm; - type IdType; - async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result - where - Self: Sized; - async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result - where - Self: Sized; + type IdType: Send; + + async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result; + + async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result { + let query: Find = Self::table().find(id); + let conn = &mut *get_conn(pool).await?; + query.first::(conn).await + } + /// when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column. async fn update( pool: &mut DbPool<'_>, id: Self::IdType, form: &Self::UpdateForm, - ) -> Result - where - Self: Sized; - async fn delete(_pool: &mut DbPool<'_>, _id: Self::IdType) -> Result - where - Self: Sized, - Self::IdType: Send, - { - async { Err(Error::NotFound) }.await + ) -> Result; + + async fn delete(pool: &mut DbPool<'_>, id: Self::IdType) -> Result { + let query: Delete> = diesel::delete(Self::table().find(id)); + let conn = &mut *get_conn(pool).await?; + query.execute(conn).await } } From 7bc64ab91a7b6c2097d287afd397395baa574ff3 Mon Sep 17 00:00:00 2001 From: Louis GERARD Date: Wed, 2 Aug 2023 11:32:16 +0200 Subject: [PATCH 06/11] Remove follow community traits (#3737) * chore(FollowCommunity): remove Perform and Send Activity traits * chore(FollowCommunity): avoid fetching community and person from db --- crates/api/src/community/follow.rs | 93 +++++++++++---------- crates/api/src/community/mod.rs | 2 +- crates/api_common/src/send_activity.rs | 1 + crates/apub/src/activities/following/mod.rs | 44 ++++------ crates/apub/src/activities/mod.rs | 4 + src/api_routes_http.rs | 4 +- 6 files changed, 71 insertions(+), 77 deletions(-) diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index a2f46eb75..8fea2625d 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; 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}, }; use lemmy_db_schema::{ @@ -15,54 +16,56 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for FollowCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn follow_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &FollowCommunity = self; - 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, + person_id: local_user_view.person.id, + pending: false, + }; - let community_id = data.community_id; - let community = Community::read(&mut context.pool(), community_id).await?; - let mut community_follower_form = CommunityFollowerForm { - community_id: data.community_id, - person_id: local_user_view.person.id, - pending: false, - }; + if data.follow { + if community.local { + check_community_ban(local_user_view.person.id, community.id, &mut context.pool()).await?; + check_community_deleted_or_removed(community.id, &mut context.pool()).await?; - if data.follow { - if community.local { - check_community_ban(local_user_view.person.id, community_id, &mut context.pool()).await?; - check_community_deleted_or_removed(community_id, &mut context.pool()).await?; - - CommunityFollower::follow(&mut context.pool(), &community_follower_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; - } else { - // Mark as pending, the actual federation activity is sent via `SendActivity` handler - community_follower_form.pending = true; - CommunityFollower::follow(&mut context.pool(), &community_follower_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; - } - } - if !data.follow { - CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + CommunityFollower::follow(&mut context.pool(), &community_follower_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; + } else { + // Mark as pending, the actual federation activity is sent via `SendActivity` handler + community_follower_form.pending = true; + CommunityFollower::follow(&mut context.pool(), &community_follower_form) .await .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; } - - let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; - let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; - - Ok(Self::Response { - community_view, - discussion_languages, - }) } + if !data.follow { + CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; + } + + ActivityChannel::submit_activity( + SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow), + &context, + ) + .await?; + + let community_id = data.community_id; + let person_id = local_user_view.person.id; + let community_view = + CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; + let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; + + Ok(Json(CommunityResponse { + community_view, + discussion_languages, + })) } diff --git a/crates/api/src/community/mod.rs b/crates/api/src/community/mod.rs index fda082657..fc3ef67c5 100644 --- a/crates/api/src/community/mod.rs +++ b/crates/api/src/community/mod.rs @@ -1,6 +1,6 @@ mod add_mod; mod ban; mod block; -mod follow; +pub mod follow; mod hide; mod transfer; diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 7954db284..8580c2175 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -31,6 +31,7 @@ pub enum SendActivityData { RemoveComment(Comment, Person, Community, Option), UpdateComment(Comment), LikePostOrComment(DbUrl, Person, Community, i16), + FollowCommunity(Community, Person, bool), } // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with diff --git a/crates/apub/src/activities/following/mod.rs b/crates/apub/src/activities/following/mod.rs index 06f95e3f4..c4f0bd0b7 100644 --- a/crates/apub/src/activities/following/mod.rs +++ b/crates/apub/src/activities/following/mod.rs @@ -1,41 +1,27 @@ use crate::{ - objects::community::ApubCommunity, + objects::{community::ApubCommunity, person::ApubPerson}, protocol::activities::following::{follow::Follow, undo_follow::UndoFollow}, - SendActivity, }; use activitypub_federation::config::Data; -use lemmy_api_common::{ - community::{CommunityResponse, FollowCommunity}, - context::LemmyContext, - utils::local_user_view_from_jwt, -}; -use lemmy_db_schema::{source::community::Community, traits::Crud}; +use lemmy_api_common::context::LemmyContext; +use lemmy_db_schema::source::{community::Community, person::Person}; use lemmy_utils::error::LemmyError; pub mod accept; pub mod follow; pub mod undo_follow; -#[async_trait::async_trait] -impl SendActivity for FollowCommunity { - type Response = CommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let person = local_user_view.person.clone().into(); - let community: ApubCommunity = Community::read(&mut context.pool(), request.community_id) - .await? - .into(); - if community.local { - Ok(()) - } else if request.follow { - Follow::send(&person, &community, context).await - } else { - UndoFollow::send(&person, &community, context).await - } +pub async fn send_follow_community( + community: Community, + person: Person, + follow: bool, + context: &Data, +) -> Result<(), LemmyError> { + let community: ApubCommunity = community.into(); + let actor: ApubPerson = person.into(); + if follow { + Follow::send(&actor, &community, context).await + } else { + UndoFollow::send(&actor, &community, context).await } } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index c577f8bc9..780755766 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -1,3 +1,4 @@ +use self::following::send_follow_community; use crate::{ activities::{ deletion::{send_apub_delete_in_community, DeletableObjects}, @@ -250,6 +251,9 @@ pub async fn match_outgoing_activities( LikePostOrComment(object_id, person, community, score) => { send_like_activity(object_id, person, community, score, context).await } + SendActivityData::FollowCommunity(community, person, follow) => { + send_follow_community(community, person, follow, &context).await + } } }; if *SYNCHRONOUS_FEDERATION { diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index 6d538e63e..dccf18dd4 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -2,6 +2,7 @@ use actix_web::{guard, web, Error, HttpResponse, Result}; use lemmy_api::{ comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment}, comment_report::{list::list_comment_reports, resolve::resolve_comment_report}, + community::follow::follow_community, local_user::notifications::mark_reply_read::mark_reply_as_read, post::like::like_post, Perform, @@ -15,7 +16,6 @@ use lemmy_api_common::{ CreateCommunity, DeleteCommunity, EditCommunity, - FollowCommunity, HideCommunity, RemoveCommunity, TransferCommunity, @@ -146,7 +146,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("", web::put().to(route_post_crud::)) .route("/hide", web::put().to(route_post::)) .route("/list", web::get().to(list_communities)) - .route("/follow", web::post().to(route_post::)) + .route("/follow", web::post().to(follow_community)) .route("/block", web::post().to(route_post::)) .route( "/delete", From 58388f2ce8a4dccfc9faf03bffc3656993c97e85 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 2 Aug 2023 18:29:21 +0200 Subject: [PATCH 07/11] Only run slow CI checks for actual code changes (attempt 2) (#3759) * Only run slow CI checks for actual code changes (attempt 2) * use when path include * change rust * update * x * y * zsad * remove println * fmt * readme * Revert "readme" This reverts commit d58b6ad9731d8c6009d8680d0126d9e9f0af3103. * ci * gitmodules --- .woodpecker.yml | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 58ab2f0f9..91779122a 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -3,6 +3,22 @@ variables: - &muslrust_image "clux/muslrust:1.70.0" + - &slow_check_paths + - path: + # rust source code + - "**/*.rs" + - "**/Cargo.toml" + - "Cargo.lock" + # database migrations + - "migrations" + # typescript tests + - "api_tests" + # config files and scripts used by ci + - ".woodpecker.yml" + - ".rustfmt.toml" + - "scripts/update_config_defaults.sh" + - "diesel.toml" + - ".gitmodules" # Broken for cron jobs currently, see # https://github.com/woodpecker-ci/woodpecker/issues/1716 @@ -48,6 +64,7 @@ pipeline: - "api_tests/node_modules" secrets: [MINIO_ENDPOINT, MINIO_WRITE_USER, MINIO_WRITE_PASSWORD, MINIO_BUCKET] + when: *slow_check_paths toml_fmt: image: tamasfe/taplo:0.8.1 @@ -65,8 +82,6 @@ pipeline: - rustup toolchain install nightly-2023-07-10 - rustup component add rustfmt --toolchain nightly-2023-07-10 - cargo +nightly-2023-07-10 fmt -- --check - # when: - # platform: linux/amd64 # make sure api builds with default features (used by other crates relying on lemmy api) check_api_common_default_features: @@ -75,8 +90,7 @@ pipeline: CARGO_HOME: .cargo commands: - cargo check --package lemmy_api_common - # when: - # platform: linux/amd64 + when: *slow_check_paths lemmy_api_common_doesnt_depend_on_diesel: image: *muslrust_image @@ -84,8 +98,7 @@ pipeline: CARGO_HOME: .cargo commands: - "! cargo tree -p lemmy_api_common --no-default-features -i diesel" - # when: - # platform: linux/amd64 + when: *slow_check_paths lemmy_api_common_works_with_wasm: image: *muslrust_image @@ -94,6 +107,7 @@ pipeline: commands: - "rustup target add wasm32-unknown-unknown" - "cargo check --target wasm32-unknown-unknown -p lemmy_api_common" + when: *slow_check_paths check_defaults_hjson_updated: image: *muslrust_image @@ -103,8 +117,7 @@ pipeline: - export LEMMY_CONFIG_LOCATION=./config/config.hjson - ./scripts/update_config_defaults.sh config/defaults_current.hjson - diff config/defaults.hjson config/defaults_current.hjson - # when: - # platform: linux/amd64 + when: *slow_check_paths check_diesel_schema: image: willsquire/diesel-cli @@ -115,6 +128,7 @@ pipeline: - diesel migration run - diesel print-schema --config-file=diesel.toml > tmp.schema - diff tmp.schema crates/db_schema/src/schema.rs + when: *slow_check_paths check_diesel_migration_revertable: image: willsquire/diesel-cli @@ -124,6 +138,7 @@ pipeline: commands: - diesel migration run - diesel migration redo + when: *slow_check_paths cargo_clippy: image: *muslrust_image @@ -147,8 +162,7 @@ pipeline: -D clippy::needless_collect -D clippy::unwrap_used -D clippy::indexing_slicing - # when: - # platform: linux/amd64 + when: *slow_check_paths cargo_test: image: *muslrust_image @@ -159,8 +173,7 @@ pipeline: commands: - export LEMMY_CONFIG_LOCATION=../../config/config.hjson - cargo test --workspace --no-fail-fast - # when: - # platform: linux/amd64 + when: *slow_check_paths cargo_build: image: *muslrust_image @@ -169,8 +182,7 @@ pipeline: commands: - cargo build - mv target/x86_64-unknown-linux-musl/debug/lemmy_server target/lemmy_server - # when: - # platform: linux/amd64 + when: *slow_check_paths run_federation_tests: image: node:alpine @@ -183,8 +195,7 @@ pipeline: - cd api_tests/ - yarn - yarn api-test - # when: - # platform: linux/amd64 + when: *slow_check_paths rebuild-cache: image: meltwater/drone-cache:v1 @@ -208,6 +219,7 @@ pipeline: - "api_tests/node_modules" secrets: [MINIO_ENDPOINT, MINIO_WRITE_USER, MINIO_WRITE_PASSWORD, MINIO_BUCKET] + when: *slow_check_paths publish_release_docker: image: woodpeckerci/plugin-docker-buildx @@ -257,5 +269,3 @@ services: environment: POSTGRES_USER: lemmy POSTGRES_PASSWORD: password - # when: - # platform: linux/amd64 From b4380cb548f507ab53fa0808ab21d8270646cb36 Mon Sep 17 00:00:00 2001 From: RocketDerp <113625597+RocketDerp@users.noreply.github.com> Date: Wed, 2 Aug 2023 09:31:28 -0700 Subject: [PATCH 08/11] Do not hide read posts when it is a user profile view (#3791) --- crates/db_views/src/post_view.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 9f6d0735f..3243bca88 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -308,7 +308,10 @@ fn queries<'a>() -> Queries< .map(|l| l.local_user.show_read_posts) .unwrap_or(true) { - query = query.filter(post_read::post_id.is_null()); + // Do not hide read posts when it is a user profile view + if !is_profile_view { + query = query.filter(post_read::post_id.is_null()); + } } if options.local_user.is_some() { From be1389420b9dc4516f1e9b3e82637f84919a438e Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 2 Aug 2023 12:44:51 -0400 Subject: [PATCH 09/11] Adding SQL format checking via `pg_format` / pgFormatter (#3740) * SQL format checking, 1. * SQL format checking, 2. * SQL format checking, 3. * SQL format checking, 4. * SQL format checking, 5. * Running pg_format * Getting rid of comment. * Upping pg_format version. * Using git ls-files for sql format check. * Fixing sql lints. * Addressing PR comments. --- .woodpecker.yml | 14 +- .../down.sql | 5 +- .../up.sql | 26 +- .../2019-02-26-002946_create_user/down.sql | 6 +- .../2019-02-26-002946_create_user/up.sql | 40 +- .../down.sql | 20 +- .../2019-02-27-170003_create_community/up.sql | 134 +- .../2019-03-03-163336_create_post/down.sql | 12 +- .../2019-03-03-163336_create_post/up.sql | 61 +- .../2019-03-05-233828_create_comment/down.sql | 9 +- .../2019-03-05-233828_create_comment/up.sql | 49 +- .../down.sql | 6 +- .../2019-03-30-212058_create_post_view/up.sql | 148 +- .../down.sql | 15 +- .../up.sql | 195 +- .../down.sql | 6 +- .../up.sql | 166 +- .../down.sql | 24 +- .../up.sql | 116 +- .../down.sql | 3 +- .../2019-04-08-015947_create_user_view/up.sql | 55 +- .../down.sql | 24 +- .../2019-04-11-144915_create_mod_views/up.sql | 311 ++- .../down.sql | 418 ++-- .../up.sql | 426 ++-- .../down.sql | 92 +- .../up.sql | 99 +- .../2019-06-01-222649_remove_admin/down.sql | 4 +- .../2019-06-01-222649_remove_admin/up.sql | 4 +- .../down.sql | 256 ++- .../2019-08-11-000918_add_nsfw_columns/up.sql | 262 ++- .../down.sql | 37 +- .../up.sql | 43 +- .../down.sql | 151 +- .../up.sql | 169 +- .../down.sql | 176 +- .../up.sql | 227 ++- .../2019-10-15-181630_add_themes/down.sql | 4 +- .../2019-10-15-181630_add_themes/up.sql | 4 +- .../down.sql | 6 +- .../up.sql | 28 +- .../down.sql | 8 +- .../up.sql | 8 +- .../down.sql | 3 +- .../up.sql | 11 +- .../2019-12-09-060754_add_lang/down.sql | 4 +- migrations/2019-12-09-060754_add_lang/up.sql | 4 +- .../down.sql | 54 +- .../2019-12-11-181820_add_site_fields/up.sql | 54 +- .../2019-12-29-164820_add_avatar/down.sql | 643 ++++-- .../2019-12-29-164820_add_avatar/up.sql | 701 +++++-- .../down.sql | 60 +- .../up.sql | 62 +- .../down.sql | 69 +- .../up.sql | 73 +- .../2020-01-11-012452_add_indexes/down.sql | 32 +- .../2020-01-11-012452_add_indexes/up.sql | 32 +- .../down.sql | 618 ++++-- .../up.sql | 1007 ++++++---- .../down.sql | 88 +- .../up.sql | 155 +- .../down.sql | 58 +- .../up.sql | 57 +- .../down.sql | 3 +- .../up.sql | 60 +- .../down.sql | 6 +- .../up.sql | 31 +- .../down.sql | 509 +++-- .../up.sql | 509 +++-- .../down.sql | 336 ++-- .../up.sql | 372 ++-- .../down.sql | 276 ++- .../up.sql | 313 ++- .../down.sql | 328 ++- .../up.sql | 330 ++- .../down.sql | 29 +- .../up.sql | 43 +- .../down.sql | 13 +- .../up.sql | 15 +- .../down.sql | 87 +- .../up.sql | 86 +- .../down.sql | 1032 +++++++--- .../up.sql | 1292 ++++++++---- .../down.sql | 5 +- .../up.sql | 6 +- .../down.sql | 41 +- .../up.sql | 51 +- .../down.sql | 1233 ++++++++---- .../2020-06-30-135809_remove_mat_views/up.sql | 1765 ++++++++++------- .../down.sql | 677 ++++--- .../up.sql | 681 ++++--- .../down.sql | 399 ++-- .../up.sql | 403 ++-- .../down.sql | 42 +- .../up.sql | 94 +- .../down.sql | 1361 +++++++------ .../up.sql | 1395 +++++++------ .../down.sql | 168 +- .../up.sql | 168 +- .../down.sql | 68 +- .../up.sql | 129 +- .../down.sql | 3 +- .../up.sql | 200 +- .../down.sql | 365 ++-- .../up.sql | 387 ++-- .../down.sql | 226 ++- .../up.sql | 266 ++- .../down.sql | 12 +- .../up.sql | 173 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 8 +- .../up.sql | 8 +- .../down.sql | 4 +- .../up.sql | 4 +- .../2020-11-26-134531_delete_user/down.sql | 4 +- .../2020-11-26-134531_delete_user/up.sql | 4 +- .../down.sql | 42 +- .../up.sql | 355 ++-- .../down.sql | 26 +- .../up.sql | 376 ++-- .../down.sql | 22 +- .../up.sql | 283 +-- .../down.sql | 22 +- .../up.sql | 287 +-- .../down.sql | 14 +- .../up.sql | 170 +- .../down.sql | 3 +- .../up.sql | 22 +- .../down.sql | 6 +- .../up.sql | 74 +- .../down.sql | 35 +- .../up.sql | 55 +- .../down.sql | 16 +- .../2021-01-26-173850_default_actor_id/up.sql | 16 +- .../down.sql | 26 +- .../up.sql | 221 ++- .../down.sql | 3 +- .../up.sql | 3 +- .../2021-02-02-153240_apub_columns/down.sql | 19 +- .../2021-02-02-153240_apub_columns/up.sql | 30 +- .../down.sql | 68 +- .../up.sql | 77 +- .../down.sql | 79 +- .../up.sql | 80 +- .../down.sql | 64 +- .../up.sql | 5 +- .../down.sql | 3 +- .../up.sql | 8 +- .../down.sql | 4 +- .../2021-03-04-040229_clean_icon_urls/up.sql | 32 +- .../down.sql | 700 ++++--- .../up.sql | 742 ++++--- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 46 +- .../up.sql | 46 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 24 +- .../2021-03-31-105915_add_bot_account/up.sql | 24 +- .../down.sql | 7 +- .../up.sql | 6 +- .../down.sql | 19 +- .../up.sql | 19 +- .../down.sql | 3 +- .../up.sql | 2 +- .../down.sql | 34 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 30 +- .../up.sql | 30 +- .../down.sql | 65 +- .../up.sql | 135 +- .../down.sql | 6 +- .../up.sql | 25 +- .../down.sql | 100 +- .../up.sql | 117 +- .../down.sql | 3 +- .../up.sql | 15 +- .../2021-09-20-112945_jwt-secret/down.sql | 3 +- .../2021-09-20-112945_jwt-secret/up.sql | 10 +- .../down.sql | 12 +- .../up.sql | 46 +- .../down.sql | 8 +- .../up.sql | 31 +- .../down.sql | 8 +- .../up.sql | 15 +- .../down.sql | 6 +- .../up.sql | 6 +- .../down.sql | 18 +- .../up.sql | 25 +- .../down.sql | 17 +- .../up.sql | 33 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 23 +- .../up.sql | 23 +- .../down.sql | 6 +- .../up.sql | 17 +- .../down.sql | 26 +- .../up.sql | 4 +- .../2022-01-28-104106_instance-actor/down.sql | 13 +- .../2022-01-28-104106_instance-actor/up.sql | 13 +- .../down.sql | 3 +- .../up.sql | 3 +- .../2022-02-18-210946_default_theme/down.sql | 4 +- .../2022-02-18-210946_default_theme/up.sql | 4 +- .../down.sql | 533 ++--- .../up.sql | 676 ++++--- .../down.sql | 14 +- .../up.sql | 11 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 3 +- .../up.sql | 3 +- .../down.sql | 8 +- .../up.sql | 8 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../2022-05-20-135341_embed-url/down.sql | 8 +- migrations/2022-05-20-135341_embed-url/up.sql | 8 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../2022-06-21-123144_language-tags/down.sql | 11 +- .../2022-06-21-123144_language-tags/up.sql | 951 +++++++-- .../2022-07-07-182650_comment_ltrees/down.sql | 44 +- .../2022-07-07-182650_comment_ltrees/up.sql | 220 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 3 +- .../up.sql | 15 +- .../down.sql | 4 +- .../up.sql | 5 +- .../down.sql | 3 +- .../up.sql | 26 +- .../2022-09-07-114618_pm-reports/down.sql | 3 +- .../2022-09-07-114618_pm-reports/up.sql | 23 +- .../down.sql | 9 +- .../up.sql | 88 +- .../down.sql | 14 +- .../up.sql | 3 +- .../down.sql | 129 +- .../up.sql | 318 +-- .../down.sql | 3 +- .../2022-11-13-181529_create_taglines/up.sql | 15 +- .../2022-11-20-032430_sticky_local/down.sql | 90 +- .../2022-11-20-032430_sticky_local/up.sql | 111 +- .../down.sql | 8 +- .../up.sql | 8 +- .../2022-11-21-204256_user-following/down.sql | 6 +- .../2022-11-21-204256_user-following/up.sql | 26 +- .../down.sql | 69 +- .../up.sql | 51 +- .../down.sql | 30 +- .../up.sql | 38 +- .../down.sql | 10 +- .../2023-02-01-012747_fix_active_index/up.sql | 10 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 8 +- .../up.sql | 8 +- .../2023-02-11-173347_custom_emojis/down.sql | 6 +- .../2023-02-11-173347_custom_emojis/up.sql | 31 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 8 +- .../up.sql | 7 +- .../down.sql | 3 +- .../up.sql | 6 +- .../down.sql | 8 +- .../2023-02-16-194139_add_totp_secret/up.sql | 8 +- .../down.sql | 158 +- .../up.sql | 175 +- .../down.sql | 63 +- .../up.sql | 54 +- .../up.sql | 13 +- .../2023-06-06-104440_index_post_url/down.sql | 6 +- .../2023-06-06-104440_index_post_url/up.sql | 15 +- .../down.sql | 54 +- .../up.sql | 78 +- .../down.sql | 32 +- .../up.sql | 12 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 35 +- .../up.sql | 147 +- .../down.sql | 35 +- .../up.sql | 12 +- .../2023-06-21-153242_add_captcha/down.sql | 3 +- .../2023-06-21-153242_add_captcha/up.sql | 11 +- .../down.sql | 4 +- .../up.sql | 16 +- .../down.sql | 8 +- .../up.sql | 8 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 6 +- .../up.sql | 5 +- .../down.sql | 8 +- .../2023-06-27-065106_add_ui_settings/up.sql | 8 +- .../down.sql | 63 +- .../up.sql | 61 +- .../2023-07-05-000058_person-admin/down.sql | 6 +- .../2023-07-05-000058_person-admin/up.sql | 9 +- .../down.sql | 4 +- .../2023-07-06-151124_hot-rank-future/up.sql | 4 +- .../down.sql | 212 +- .../up.sql | 151 +- .../down.sql | 4 +- .../up.sql | 4 +- .../down.sql | 35 +- .../up.sql | 59 +- .../down.sql | 50 +- .../up.sql | 50 +- .../down.sql | 5 +- .../up.sql | 15 +- .../down.sql | 17 +- .../up.sql | 36 +- .../down.sql | 8 +- .../up.sql | 10 +- .../2023-07-24-232635_trigram-index/up.sql | 8 +- .../down.sql | 158 +- .../up.sql | 245 ++- .../down.sql | 27 +- .../up.sql | 45 +- .../down.sql | 186 +- .../up.sql | 115 +- scripts/{fix-clippy.sh => lint.sh} | 6 + scripts/sql_format_check.sh | 15 + 341 files changed, 22860 insertions(+), 12364 deletions(-) rename scripts/{fix-clippy.sh => lint.sh} (87%) create mode 100755 scripts/sql_format_check.sh diff --git a/.woodpecker.yml b/.woodpecker.yml index 91779122a..a3c1f1194 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -83,6 +83,18 @@ pipeline: - rustup component add rustfmt --toolchain nightly-2023-07-10 - cargo +nightly-2023-07-10 fmt -- --check + sql_fmt: + image: alpine:3 + commands: + - apk add bash wget perl make git + - wget https://github.com/darold/pgFormatter/archive/refs/tags/v5.5.tar.gz + - tar xzf v5.5.tar.gz + - cd pgFormatter-5.5 + - perl Makefile.PL + - make && make install + - cd .. + - ./scripts/./sql_format_check.sh + # make sure api builds with default features (used by other crates relying on lemmy api) check_api_common_default_features: image: *muslrust_image @@ -145,7 +157,7 @@ pipeline: environment: CARGO_HOME: .cargo commands: - # when adding new clippy lints, make sure to also add them in scripts/fix-clippy.sh + # when adding new clippy lints, make sure to also add them in scripts/lint.sh - rustup component add clippy - cargo clippy --workspace --tests --all-targets --features console -- -D warnings -D deprecated -D clippy::perf -D clippy::complexity diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql index a9f526091..5e29318c8 100644 --- a/migrations/00000000000000_diesel_initial_setup/down.sql +++ b/migrations/00000000000000_diesel_initial_setup/down.sql @@ -1,6 +1,7 @@ -- This file was automatically created by Diesel to setup helper functions -- and other internal bookkeeping. This file is safe to edit, any future -- changes will be added to existing projects as new migrations. +DROP FUNCTION IF EXISTS diesel_manage_updated_at (_tbl regclass); + +DROP FUNCTION IF EXISTS diesel_set_updated_at (); -DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); -DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql index d68895b1a..246f5e474 100644 --- a/migrations/00000000000000_diesel_initial_setup/up.sql +++ b/migrations/00000000000000_diesel_initial_setup/up.sql @@ -1,10 +1,6 @@ -- This file was automatically created by Diesel to setup helper functions -- and other internal bookkeeping. This file is safe to edit, any future -- changes will be added to existing projects as new migrations. - - - - -- Sets up a trigger for the given table to automatically set a column called -- `updated_at` whenever the row is modified (unless `updated_at` was included -- in the modified columns) @@ -16,21 +12,25 @@ -- -- SELECT diesel_manage_updated_at('users'); -- ``` -CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION diesel_manage_updated_at (_tbl regclass) + RETURNS VOID + AS $$ BEGIN EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); END; -$$ LANGUAGE plpgsql; +$$ +LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ +CREATE OR REPLACE FUNCTION diesel_set_updated_at () + RETURNS TRIGGER + AS $$ BEGIN - IF ( - NEW IS DISTINCT FROM OLD AND - NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at - ) THEN - NEW.updated_at := current_timestamp; + IF (NEW IS DISTINCT FROM OLD AND NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at) THEN + NEW.updated_at := CURRENT_TIMESTAMP; END IF; RETURN NEW; END; -$$ LANGUAGE plpgsql; +$$ +LANGUAGE plpgsql; + diff --git a/migrations/2019-02-26-002946_create_user/down.sql b/migrations/2019-02-26-002946_create_user/down.sql index 67a280d62..a9bfa3fef 100644 --- a/migrations/2019-02-26-002946_create_user/down.sql +++ b/migrations/2019-02-26-002946_create_user/down.sql @@ -1,2 +1,4 @@ -drop table user_ban; -drop table user_; +DROP TABLE user_ban; + +DROP TABLE user_; + diff --git a/migrations/2019-02-26-002946_create_user/up.sql b/migrations/2019-02-26-002946_create_user/up.sql index ea2c9234f..251938fee 100644 --- a/migrations/2019-02-26-002946_create_user/up.sql +++ b/migrations/2019-02-26-002946_create_user/up.sql @@ -1,23 +1,25 @@ -create table user_ ( - id serial primary key, - name varchar(20) not null, - fedi_name varchar(40) not null, - preferred_username varchar(20), - password_encrypted text not null, - email text unique, - icon bytea, - admin boolean default false not null, - banned boolean default false not null, - published timestamp not null default now(), - updated timestamp, - unique(name, fedi_name) +CREATE TABLE user_ ( + id serial PRIMARY KEY, + name varchar(20) NOT NULL, + fedi_name varchar(40) NOT NULL, + preferred_username varchar(20), + password_encrypted text NOT NULL, + email text UNIQUE, + icon bytea, + admin boolean DEFAULT FALSE NOT NULL, + banned boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp, + UNIQUE (name, fedi_name) ); -create table user_ban ( - id serial primary key, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique (user_id) +CREATE TABLE user_ban ( + id serial PRIMARY KEY, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (user_id) ); -insert into user_ (name, fedi_name, password_encrypted) values ('admin', 'TBD', 'TBD'); +INSERT INTO user_ (name, fedi_name, password_encrypted) + VALUES ('admin', 'TBD', 'TBD'); + diff --git a/migrations/2019-02-27-170003_create_community/down.sql b/migrations/2019-02-27-170003_create_community/down.sql index 219588d8f..d5ecfc52d 100644 --- a/migrations/2019-02-27-170003_create_community/down.sql +++ b/migrations/2019-02-27-170003_create_community/down.sql @@ -1,6 +1,14 @@ -drop table site; -drop table community_user_ban;; -drop table community_moderator; -drop table community_follower; -drop table community; -drop table category; +DROP TABLE site; + +DROP TABLE community_user_ban; + +; + +DROP TABLE community_moderator; + +DROP TABLE community_follower; + +DROP TABLE community; + +DROP TABLE category; + diff --git a/migrations/2019-02-27-170003_create_community/up.sql b/migrations/2019-02-27-170003_create_community/up.sql index 363f99f27..be8513957 100644 --- a/migrations/2019-02-27-170003_create_community/up.sql +++ b/migrations/2019-02-27-170003_create_community/up.sql @@ -1,79 +1,81 @@ -create table category ( - id serial primary key, - name varchar(100) not null unique +CREATE TABLE category ( + id serial PRIMARY KEY, + name varchar(100) NOT NULL UNIQUE ); -insert into category (name) values -('Discussion'), -('Humor/Memes'), -('Gaming'), -('Movies'), -('TV'), -('Music'), -('Literature'), -('Comics'), -('Photography'), -('Art'), -('Learning'), -('DIY'), -('Lifestyle'), -('News'), -('Politics'), -('Society'), -('Gender/Identity/Sexuality'), -('Race/Colonisation'), -('Religion'), -('Science/Technology'), -('Programming/Software'), -('Health/Sports/Fitness'), -('Porn'), -('Places'), -('Meta'), -('Other'); +INSERT INTO category (name) + VALUES ('Discussion'), + ('Humor/Memes'), + ('Gaming'), + ('Movies'), + ('TV'), + ('Music'), + ('Literature'), + ('Comics'), + ('Photography'), + ('Art'), + ('Learning'), + ('DIY'), + ('Lifestyle'), + ('News'), + ('Politics'), + ('Society'), + ('Gender/Identity/Sexuality'), + ('Race/Colonisation'), + ('Religion'), + ('Science/Technology'), + ('Programming/Software'), + ('Health/Sports/Fitness'), + ('Porn'), + ('Places'), + ('Meta'), + ('Other'); -create table community ( - id serial primary key, - name varchar(20) not null unique, - title varchar(100) not null, - description text, - category_id int references category on update cascade on delete cascade not null, - creator_id int references user_ on update cascade on delete cascade not null, - removed boolean default false not null, - published timestamp not null default now(), - updated timestamp +CREATE TABLE community ( + id serial PRIMARY KEY, + name varchar(20) NOT NULL UNIQUE, + title varchar(100) NOT NULL, + description text, + category_id int REFERENCES category ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + removed boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); -create table community_moderator ( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique (community_id, user_id) +CREATE TABLE community_moderator ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (community_id, user_id) ); -create table community_follower ( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique (community_id, user_id) +CREATE TABLE community_follower ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (community_id, user_id) ); -create table community_user_ban ( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique (community_id, user_id) +CREATE TABLE community_user_ban ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (community_id, user_id) ); -insert into community (name, title, category_id, creator_id) values ('main', 'The Default Community', 1, 1); +INSERT INTO community (name, title, category_id, creator_id) + VALUES ('main', 'The Default Community', 1, 1); -create table site ( - id serial primary key, - name varchar(20) not null unique, - description text, - creator_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - updated timestamp +CREATE TABLE site ( + id serial PRIMARY KEY, + name varchar(20) NOT NULL UNIQUE, + description text, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); + diff --git a/migrations/2019-03-03-163336_create_post/down.sql b/migrations/2019-03-03-163336_create_post/down.sql index a671c2e76..193f1c1d4 100644 --- a/migrations/2019-03-03-163336_create_post/down.sql +++ b/migrations/2019-03-03-163336_create_post/down.sql @@ -1,4 +1,8 @@ -drop table post_read; -drop table post_saved; -drop table post_like; -drop table post; +DROP TABLE post_read; + +DROP TABLE post_saved; + +DROP TABLE post_like; + +DROP TABLE post; + diff --git a/migrations/2019-03-03-163336_create_post/up.sql b/migrations/2019-03-03-163336_create_post/up.sql index 907378129..dfdd15c2c 100644 --- a/migrations/2019-03-03-163336_create_post/up.sql +++ b/migrations/2019-03-03-163336_create_post/up.sql @@ -1,37 +1,38 @@ -create table post ( - id serial primary key, - name varchar(100) not null, - url text, -- These are both optional, a post can just have a title - body text, - creator_id int references user_ on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - removed boolean default false not null, - locked boolean default false not null, - published timestamp not null default now(), - updated timestamp +CREATE TABLE post ( + id serial PRIMARY KEY, + name varchar(100) NOT NULL, + url text, -- These are both optional, a post can just have a title + body text, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + removed boolean DEFAULT FALSE NOT NULL, + locked boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); -create table post_like ( - id serial primary key, - post_id int references post on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - score smallint not null, -- -1, or 1 for dislike, like, no row for no opinion - published timestamp not null default now(), - unique(post_id, user_id) +CREATE TABLE post_like ( + id serial PRIMARY KEY, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + score smallint NOT NULL, -- -1, or 1 for dislike, like, no row for no opinion + published timestamp NOT NULL DEFAULT now(), + UNIQUE (post_id, user_id) ); -create table post_saved ( - id serial primary key, - post_id int references post on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique(post_id, user_id) +CREATE TABLE post_saved ( + id serial PRIMARY KEY, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (post_id, user_id) ); -create table post_read ( - id serial primary key, - post_id int references post on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique(post_id, user_id) +CREATE TABLE post_read ( + id serial PRIMARY KEY, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (post_id, user_id) ); + diff --git a/migrations/2019-03-05-233828_create_comment/down.sql b/migrations/2019-03-05-233828_create_comment/down.sql index 80fe0b1f5..4c4a13cdd 100644 --- a/migrations/2019-03-05-233828_create_comment/down.sql +++ b/migrations/2019-03-05-233828_create_comment/down.sql @@ -1,3 +1,6 @@ -drop table comment_saved; -drop table comment_like; -drop table comment; +DROP TABLE comment_saved; + +DROP TABLE comment_like; + +DROP TABLE comment; + diff --git a/migrations/2019-03-05-233828_create_comment/up.sql b/migrations/2019-03-05-233828_create_comment/up.sql index 4b754ece1..ed7ea17cd 100644 --- a/migrations/2019-03-05-233828_create_comment/up.sql +++ b/migrations/2019-03-05-233828_create_comment/up.sql @@ -1,29 +1,30 @@ -create table comment ( - id serial primary key, - creator_id int references user_ on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - parent_id int references comment on update cascade on delete cascade, - content text not null, - removed boolean default false not null, - read boolean default false not null, - published timestamp not null default now(), - updated timestamp +CREATE TABLE comment ( + id serial PRIMARY KEY, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + parent_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE, + content text NOT NULL, + removed boolean DEFAULT FALSE NOT NULL, + read boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); -create table comment_like ( - id serial primary key, - user_id int references user_ on update cascade on delete cascade not null, - comment_id int references comment on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - score smallint not null, -- -1, or 1 for dislike, like, no row for no opinion - published timestamp not null default now(), - unique(comment_id, user_id) +CREATE TABLE comment_like ( + id serial PRIMARY KEY, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + score smallint NOT NULL, -- -1, or 1 for dislike, like, no row for no opinion + published timestamp NOT NULL DEFAULT now(), + UNIQUE (comment_id, user_id) ); -create table comment_saved ( - id serial primary key, - comment_id int references comment on update cascade on delete cascade not null, - user_id int references user_ on update cascade on delete cascade not null, - published timestamp not null default now(), - unique(comment_id, user_id) +CREATE TABLE comment_saved ( + id serial PRIMARY KEY, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (comment_id, user_id) ); + diff --git a/migrations/2019-03-30-212058_create_post_view/down.sql b/migrations/2019-03-30-212058_create_post_view/down.sql index 37c54d911..75f9dc992 100644 --- a/migrations/2019-03-30-212058_create_post_view/down.sql +++ b/migrations/2019-03-30-212058_create_post_view/down.sql @@ -1,2 +1,4 @@ -drop view post_view; -drop function hot_rank; +DROP VIEW post_view; + +DROP FUNCTION hot_rank; + diff --git a/migrations/2019-03-30-212058_create_post_view/up.sql b/migrations/2019-03-30-212058_create_post_view/up.sql index 4a4fd146e..7b5a8574b 100644 --- a/migrations/2019-03-30-212058_create_post_view/up.sql +++ b/migrations/2019-03-30-212058_create_post_view/up.sql @@ -1,51 +1,107 @@ -- Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity -create or replace function hot_rank( - score numeric, - published timestamp without time zone) -returns integer as $$ -begin - -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 - return floor(10000*log(greatest(1,score+3)) / power(((EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600) + 2), 1.8))::integer; -end; $$ +CREATE OR REPLACE FUNCTION hot_rank (score numeric, published timestamp without time zone) + RETURNS integer + AS $$ +BEGIN + -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 + RETURN floor(10000 * log(greatest (1, score + 3)) / power(((EXTRACT(EPOCH FROM (timezone('utc', now()) - published)) / 3600) + 2), 1.8))::integer; +END; +$$ LANGUAGE plpgsql; -create view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-04-03-155205_create_community_view/down.sql b/migrations/2019-04-03-155205_create_community_view/down.sql index 67d12f6fe..494b82578 100644 --- a/migrations/2019-04-03-155205_create_community_view/down.sql +++ b/migrations/2019-04-03-155205_create_community_view/down.sql @@ -1,5 +1,10 @@ -drop view community_view; -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view site_view; +DROP VIEW community_view; + +DROP VIEW community_moderator_view; + +DROP VIEW community_follower_view; + +DROP VIEW community_user_ban_view; + +DROP VIEW site_view; + diff --git a/migrations/2019-04-03-155205_create_community_view/up.sql b/migrations/2019-04-03-155205_create_community_view/up.sql index 7d38dbfa3..7f86e38ad 100644 --- a/migrations/2019-04-03-155205_create_community_view/up.sql +++ b/migrations/2019-04-03-155205_create_community_view/up.sql @@ -1,53 +1,154 @@ -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments - from community c +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments + FROM + community c ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac +CREATE VIEW community_moderator_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_moderator cm; -union all +CREATE VIEW community_follower_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cf.community_id = c.id) AS community_name +FROM + community_follower cf; -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +CREATE VIEW community_user_ban_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_user_ban cm; -create view community_moderator_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select name from community c where cm.community_id = c.id) as community_name -from community_moderator cm; +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments +FROM + site s; -create view community_follower_view as -select *, -(select name from user_ u where cf.user_id = u.id) as user_name, -(select name from community c where cf.community_id = c.id) as community_name -from community_follower cf; - -create view community_user_ban_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select name from community c where cm.community_id = c.id) as community_name -from community_user_ban cm; - -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments -from site s; diff --git a/migrations/2019-04-03-155309_create_comment_view/down.sql b/migrations/2019-04-03-155309_create_comment_view/down.sql index c19d5ff7e..223132235 100644 --- a/migrations/2019-04-03-155309_create_comment_view/down.sql +++ b/migrations/2019-04-03-155309_create_comment_view/down.sql @@ -1,2 +1,4 @@ -drop view reply_view; -drop view comment_view; +DROP VIEW reply_view; + +DROP VIEW comment_view; + diff --git a/migrations/2019-04-03-155309_create_comment_view/up.sql b/migrations/2019-04-03-155309_create_comment_view/up.sql index 24ce98fcc..dee4b97bf 100644 --- a/migrations/2019-04-03-155309_create_comment_view/up.sql +++ b/migrations/2019-04-03-155309_create_comment_view/up.sql @@ -1,60 +1,114 @@ -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id ) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select - ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; - -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; diff --git a/migrations/2019-04-07-003142_create_moderation_logs/down.sql b/migrations/2019-04-07-003142_create_moderation_logs/down.sql index 888a87feb..aa2fd8159 100644 --- a/migrations/2019-04-07-003142_create_moderation_logs/down.sql +++ b/migrations/2019-04-07-003142_create_moderation_logs/down.sql @@ -1,8 +1,16 @@ -drop table mod_remove_post; -drop table mod_lock_post; -drop table mod_remove_comment; -drop table mod_remove_community; -drop table mod_ban; -drop table mod_ban_from_community; -drop table mod_add; -drop table mod_add_community; +DROP TABLE mod_remove_post; + +DROP TABLE mod_lock_post; + +DROP TABLE mod_remove_comment; + +DROP TABLE mod_remove_community; + +DROP TABLE mod_ban; + +DROP TABLE mod_ban_from_community; + +DROP TABLE mod_add; + +DROP TABLE mod_add_community; + diff --git a/migrations/2019-04-07-003142_create_moderation_logs/up.sql b/migrations/2019-04-07-003142_create_moderation_logs/up.sql index 3b320d810..718723c9f 100644 --- a/migrations/2019-04-07-003142_create_moderation_logs/up.sql +++ b/migrations/2019-04-07-003142_create_moderation_logs/up.sql @@ -1,76 +1,76 @@ -create table mod_remove_post ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - reason text, - removed boolean default true, - when_ timestamp not null default now() +CREATE TABLE mod_remove_post ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + removed boolean DEFAULT TRUE, + when_ timestamp NOT NULL DEFAULT now() ); -create table mod_lock_post ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - locked boolean default true, - when_ timestamp not null default now() +CREATE TABLE mod_lock_post ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + locked boolean DEFAULT TRUE, + when_ timestamp NOT NULL DEFAULT now() ); -create table mod_remove_comment ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - comment_id int references comment on update cascade on delete cascade not null, - reason text, - removed boolean default true, - when_ timestamp not null default now() +CREATE TABLE mod_remove_comment ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + removed boolean DEFAULT TRUE, + when_ timestamp NOT NULL DEFAULT now() ); -create table mod_remove_community ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - reason text, - removed boolean default true, - expires timestamp, - when_ timestamp not null default now() +CREATE TABLE mod_remove_community ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + removed boolean DEFAULT TRUE, + expires timestamp, + when_ timestamp NOT NULL DEFAULT now() ); -- TODO make sure you can't ban other mods -create table mod_ban_from_community ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - other_user_id int references user_ on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - reason text, - banned boolean default true, - expires timestamp, - when_ timestamp not null default now() +CREATE TABLE mod_ban_from_community ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + other_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + banned boolean DEFAULT TRUE, + expires timestamp, + when_ timestamp NOT NULL DEFAULT now() ); -create table mod_ban ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - other_user_id int references user_ on update cascade on delete cascade not null, - reason text, - banned boolean default true, - expires timestamp, - when_ timestamp not null default now() +CREATE TABLE mod_ban ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + other_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + banned boolean DEFAULT TRUE, + expires timestamp, + when_ timestamp NOT NULL DEFAULT now() ); -create table mod_add_community ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - other_user_id int references user_ on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - removed boolean default false, - when_ timestamp not null default now() +CREATE TABLE mod_add_community ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + other_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + removed boolean DEFAULT FALSE, + when_ timestamp NOT NULL DEFAULT now() ); -- When removed is false that means kicked -create table mod_add ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - other_user_id int references user_ on update cascade on delete cascade not null, - removed boolean default false, - when_ timestamp not null default now() +CREATE TABLE mod_add ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + other_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + removed boolean DEFAULT FALSE, + when_ timestamp NOT NULL DEFAULT now() ); diff --git a/migrations/2019-04-08-015947_create_user_view/down.sql b/migrations/2019-04-08-015947_create_user_view/down.sql index c94d94c47..eec122848 100644 --- a/migrations/2019-04-08-015947_create_user_view/down.sql +++ b/migrations/2019-04-08-015947_create_user_view/down.sql @@ -1 +1,2 @@ -drop view user_view; +DROP VIEW user_view; + diff --git a/migrations/2019-04-08-015947_create_user_view/up.sql b/migrations/2019-04-08-015947_create_user_view/up.sql index 08eb56ca0..a65905935 100644 --- a/migrations/2019-04-08-015947_create_user_view/up.sql +++ b/migrations/2019-04-08-015947_create_user_view/up.sql @@ -1,12 +1,43 @@ -create view user_view as -select id, -name, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + id, + name, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + diff --git a/migrations/2019-04-11-144915_create_mod_views/down.sql b/migrations/2019-04-11-144915_create_mod_views/down.sql index 95018f35a..bf3b8bbf6 100644 --- a/migrations/2019-04-11-144915_create_mod_views/down.sql +++ b/migrations/2019-04-11-144915_create_mod_views/down.sql @@ -1,8 +1,16 @@ -drop view mod_remove_post_view; -drop view mod_lock_post_view; -drop view mod_remove_comment_view; -drop view mod_remove_community_view; -drop view mod_ban_from_community_view; -drop view mod_ban_view; -drop view mod_add_community_view; -drop view mod_add_view; +DROP VIEW mod_remove_post_view; + +DROP VIEW mod_lock_post_view; + +DROP VIEW mod_remove_comment_view; + +DROP VIEW mod_remove_community_view; + +DROP VIEW mod_ban_from_community_view; + +DROP VIEW mod_ban_view; + +DROP VIEW mod_add_community_view; + +DROP VIEW mod_add_view; + diff --git a/migrations/2019-04-11-144915_create_mod_views/up.sql b/migrations/2019-04-11-144915_create_mod_views/up.sql index 70a33e469..b252a4ba9 100644 --- a/migrations/2019-04-11-144915_create_mod_views/up.sql +++ b/migrations/2019-04-11-144915_create_mod_views/up.sql @@ -1,59 +1,266 @@ -create view mod_remove_post_view as -select mrp.*, -(select name from user_ u where mrp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mrp.post_id = p.id) as post_name, -(select c.id from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_name -from mod_remove_post mrp; +CREATE VIEW mod_remove_post_view AS +SELECT + mrp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mrp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_remove_post mrp; -create view mod_lock_post_view as -select mlp.*, -(select name from user_ u where mlp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mlp.post_id = p.id) as post_name, -(select c.id from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_name -from mod_lock_post mlp; +CREATE VIEW mod_lock_post_view AS +SELECT + mlp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mlp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mlp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_lock_post mlp; -create view mod_remove_comment_view as -select mrc.*, -(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name, -(select c.id from comment c where mrc.comment_id = c.id) as comment_user_id, -(select name from user_ u, comment c where mrc.comment_id = c.id and u.id = c.creator_id) as comment_user_name, -(select content from comment c where mrc.comment_id = c.id) as comment_content, -(select p.id from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_id, -(select p.name from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_name, -(select co.id from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_id, -(select co.name from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_name -from mod_remove_comment mrc; +CREATE VIEW mod_remove_comment_view AS +SELECT + mrc.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrc.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + c.id + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_user_id, + ( + SELECT + name + FROM + user_ u, + comment c + WHERE + mrc.comment_id = c.id + AND u.id = c.creator_id) AS comment_user_name, + ( + SELECT + content + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_content, + ( + SELECT + p.id + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_id, + ( + SELECT + p.name + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_name, + ( + SELECT + co.id + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_id, + ( + SELECT + co.name + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_name +FROM + mod_remove_comment mrc; -create view mod_remove_community_view as -select mrc.*, -(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name, -(select c.name from community c where mrc.community_id = c.id) as community_name -from mod_remove_community mrc; +CREATE VIEW mod_remove_community_view AS +SELECT + mrc.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrc.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + c.name + FROM + community c + WHERE + mrc.community_id = c.id) AS community_name +FROM + mod_remove_community mrc; -create view mod_ban_from_community_view as -select mb.*, -(select name from user_ u where mb.mod_user_id = u.id) as mod_user_name, -(select name from user_ u where mb.other_user_id = u.id) as other_user_name, -(select name from community c where mb.community_id = c.id) as community_name -from mod_ban_from_community mb; +CREATE VIEW mod_ban_from_community_view AS +SELECT + mb.*, + ( + SELECT + name + FROM + user_ u + WHERE + mb.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + user_ u + WHERE + mb.other_user_id = u.id) AS other_user_name, + ( + SELECT + name + FROM + community c + WHERE + mb.community_id = c.id) AS community_name +FROM + mod_ban_from_community mb; -create view mod_ban_view as -select mb.*, -(select name from user_ u where mb.mod_user_id = u.id) as mod_user_name, -(select name from user_ u where mb.other_user_id = u.id) as other_user_name -from mod_ban mb; +CREATE VIEW mod_ban_view AS +SELECT + mb.*, + ( + SELECT + name + FROM + user_ u + WHERE + mb.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + user_ u + WHERE + mb.other_user_id = u.id) AS other_user_name +FROM + mod_ban mb; -create view mod_add_community_view as -select ma.*, -(select name from user_ u where ma.mod_user_id = u.id) as mod_user_name, -(select name from user_ u where ma.other_user_id = u.id) as other_user_name, -(select name from community c where ma.community_id = c.id) as community_name -from mod_add_community ma; +CREATE VIEW mod_add_community_view AS +SELECT + ma.*, + ( + SELECT + name + FROM + user_ u + WHERE + ma.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + user_ u + WHERE + ma.other_user_id = u.id) AS other_user_name, + ( + SELECT + name + FROM + community c + WHERE + ma.community_id = c.id) AS community_name +FROM + mod_add_community ma; + +CREATE VIEW mod_add_view AS +SELECT + ma.*, + ( + SELECT + name + FROM + user_ u + WHERE + ma.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + user_ u + WHERE + ma.other_user_id = u.id) AS other_user_name +FROM + mod_add ma; -create view mod_add_view as -select ma.*, -(select name from user_ u where ma.mod_user_id = u.id) as mod_user_name, -(select name from user_ u where ma.other_user_id = u.id) as other_user_name -from mod_add ma; diff --git a/migrations/2019-04-29-175834_add_delete_columns/down.sql b/migrations/2019-04-29-175834_add_delete_columns/down.sql index 5e13295b2..2cb9fda3d 100644 --- a/migrations/2019-04-29-175834_add_delete_columns/down.sql +++ b/migrations/2019-04-29-175834_add_delete_columns/down.sql @@ -1,137 +1,293 @@ -drop view reply_view; -drop view comment_view; -drop view community_view; -drop view post_view; -alter table community drop column deleted; -alter table post drop column deleted; -alter table comment drop column deleted; +DROP VIEW reply_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments - from community c +DROP VIEW comment_view; + +DROP VIEW community_view; + +DROP VIEW post_view; + +ALTER TABLE community + DROP COLUMN deleted; + +ALTER TABLE post + DROP COLUMN deleted; + +ALTER TABLE comment + DROP COLUMN deleted; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments + FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -create or replace view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id -) - -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id -) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE OR REPLACE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; + +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id +) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; + +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id +) +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; diff --git a/migrations/2019-04-29-175834_add_delete_columns/up.sql b/migrations/2019-04-29-175834_add_delete_columns/up.sql index 88432dda4..05ac13896 100644 --- a/migrations/2019-04-29-175834_add_delete_columns/up.sql +++ b/migrations/2019-04-29-175834_add_delete_columns/up.sql @@ -1,141 +1,301 @@ -alter table community add column deleted boolean default false not null; -alter table post add column deleted boolean default false not null; -alter table comment add column deleted boolean default false not null; +ALTER TABLE community + ADD COLUMN deleted boolean DEFAULT FALSE NOT NULL; + +ALTER TABLE post + ADD COLUMN deleted boolean DEFAULT FALSE NOT NULL; + +ALTER TABLE comment + ADD COLUMN deleted boolean DEFAULT FALSE NOT NULL; -- The views -drop view community_view; +DROP VIEW community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments - from community c +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments + FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - - -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id -) - -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -drop view reply_view; -drop view comment_view; -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id -) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; + +DROP VIEW reply_view; + +DROP VIEW comment_view; + +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id +) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; + +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id +) +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; diff --git a/migrations/2019-05-02-051656_community_view_hot_rank/down.sql b/migrations/2019-05-02-051656_community_view_hot_rank/down.sql index 0f3a58a8b..7d3af2500 100644 --- a/migrations/2019-05-02-051656_community_view_hot_rank/down.sql +++ b/migrations/2019-05-02-051656_community_view_hot_rank/down.sql @@ -1,28 +1,68 @@ -drop view community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments - from community c +DROP VIEW community_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments + FROM + community c ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; diff --git a/migrations/2019-05-02-051656_community_view_hot_rank/up.sql b/migrations/2019-05-02-051656_community_view_hot_rank/up.sql index e7e753665..fdd79e4c9 100644 --- a/migrations/2019-05-02-051656_community_view_hot_rank/up.sql +++ b/migrations/2019-05-02-051656_community_view_hot_rank/up.sql @@ -1,29 +1,74 @@ -drop view community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +DROP VIEW community_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; diff --git a/migrations/2019-06-01-222649_remove_admin/down.sql b/migrations/2019-06-01-222649_remove_admin/down.sql index 6178857fa..926c18afc 100644 --- a/migrations/2019-06-01-222649_remove_admin/down.sql +++ b/migrations/2019-06-01-222649_remove_admin/down.sql @@ -1 +1,3 @@ -insert into user_ (name, fedi_name, password_encrypted) values ('admin', 'TBD', 'TBD'); +INSERT INTO user_ (name, fedi_name, password_encrypted) + VALUES ('admin', 'TBD', 'TBD'); + diff --git a/migrations/2019-06-01-222649_remove_admin/up.sql b/migrations/2019-06-01-222649_remove_admin/up.sql index 7cec88705..cf3d20d42 100644 --- a/migrations/2019-06-01-222649_remove_admin/up.sql +++ b/migrations/2019-06-01-222649_remove_admin/up.sql @@ -1 +1,3 @@ -delete from user_ where name like 'admin'; +DELETE FROM user_ +WHERE name LIKE 'admin'; + diff --git a/migrations/2019-08-11-000918_add_nsfw_columns/down.sql b/migrations/2019-08-11-000918_add_nsfw_columns/down.sql index 2eefece4e..12c46b7fe 100644 --- a/migrations/2019-08-11-000918_add_nsfw_columns/down.sql +++ b/migrations/2019-08-11-000918_add_nsfw_columns/down.sql @@ -1,80 +1,190 @@ -drop view community_view; -drop view post_view; -alter table community drop column nsfw; -alter table post drop column nsfw; -alter table user_ drop column show_nsfw; +DROP VIEW community_view; + +DROP VIEW post_view; + +ALTER TABLE community + DROP COLUMN nsfw; + +ALTER TABLE post + DROP COLUMN nsfw; + +ALTER TABLE user_ + DROP COLUMN show_nsfw; -- the views -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- Post view -create view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) - -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; diff --git a/migrations/2019-08-11-000918_add_nsfw_columns/up.sql b/migrations/2019-08-11-000918_add_nsfw_columns/up.sql index cc1e00740..a43718187 100644 --- a/migrations/2019-08-11-000918_add_nsfw_columns/up.sql +++ b/migrations/2019-08-11-000918_add_nsfw_columns/up.sql @@ -1,79 +1,197 @@ -alter table community add column nsfw boolean default false not null; -alter table post add column nsfw boolean default false not null; -alter table user_ add column show_nsfw boolean default false not null; +ALTER TABLE community + ADD COLUMN nsfw boolean DEFAULT FALSE NOT NULL; + +ALTER TABLE post + ADD COLUMN nsfw boolean DEFAULT FALSE NOT NULL; + +ALTER TABLE user_ + ADD COLUMN show_nsfw boolean DEFAULT FALSE NOT NULL; -- The views -drop view community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +DROP VIEW community_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -- Post view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-08-29-040006_add_community_count/down.sql b/migrations/2019-08-29-040006_add_community_count/down.sql index 6302f2675..a016508f3 100644 --- a/migrations/2019-08-29-040006_add_community_count/down.sql +++ b/migrations/2019-08-29-040006_add_community_count/down.sql @@ -1,9 +1,30 @@ -drop view site_view; +DROP VIEW site_view; + +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments +FROM + site s; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments -from site s; diff --git a/migrations/2019-08-29-040006_add_community_count/up.sql b/migrations/2019-08-29-040006_add_community_count/up.sql index 0ec1c9c33..9747ac846 100644 --- a/migrations/2019-08-29-040006_add_community_count/up.sql +++ b/migrations/2019-08-29-040006_add_community_count/up.sql @@ -1,10 +1,35 @@ -drop view site_view; +DROP VIEW site_view; + +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; diff --git a/migrations/2019-09-05-230317_add_mod_ban_views/down.sql b/migrations/2019-09-05-230317_add_mod_ban_views/down.sql index c60b672c2..2b5782e03 100644 --- a/migrations/2019-09-05-230317_add_mod_ban_views/down.sql +++ b/migrations/2019-09-05-230317_add_mod_ban_views/down.sql @@ -1,44 +1,113 @@ -- Post view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-09-05-230317_add_mod_ban_views/up.sql b/migrations/2019-09-05-230317_add_mod_ban_views/up.sql index d73b37208..94fc5754a 100644 --- a/migrations/2019-09-05-230317_add_mod_ban_views/up.sql +++ b/migrations/2019-09-05-230317_add_mod_ban_views/up.sql @@ -1,47 +1,128 @@ --- Create post view, adding banned_from_community +-- Create post view, adding banned_from_community +DROP VIEW post_view; -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-09-09-042010_add_stickied_posts/down.sql b/migrations/2019-09-09-042010_add_stickied_posts/down.sql index fb8eac8fd..838959b35 100644 --- a/migrations/2019-09-09-042010_add_stickied_posts/down.sql +++ b/migrations/2019-09-09-042010_add_stickied_posts/down.sql @@ -1,50 +1,134 @@ -drop view post_view; -drop view mod_sticky_post_view; -alter table post drop column stickied; +DROP VIEW post_view; -drop table mod_sticky_post; +DROP VIEW mod_sticky_post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +ALTER TABLE post + DROP COLUMN stickied; + +DROP TABLE mod_sticky_post; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-09-09-042010_add_stickied_posts/up.sql b/migrations/2019-09-09-042010_add_stickied_posts/up.sql index 0848f86ca..555d28744 100644 --- a/migrations/2019-09-09-042010_add_stickied_posts/up.sql +++ b/migrations/2019-09-09-042010_add_stickied_posts/up.sql @@ -1,67 +1,180 @@ -- Add the column -alter table post add column stickied boolean default false not null; +ALTER TABLE post + ADD COLUMN stickied boolean DEFAULT FALSE NOT NULL; -- Add the mod table -create table mod_sticky_post ( - id serial primary key, - mod_user_id int references user_ on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - stickied boolean default true, - when_ timestamp not null default now() +CREATE TABLE mod_sticky_post ( + id serial PRIMARY KEY, + mod_user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + stickied boolean DEFAULT TRUE, + when_ timestamp NOT NULL DEFAULT now() ); -- Add mod view -create view mod_sticky_post_view as -select msp.*, -(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name, -(select name from post p where msp.post_id = p.id) as post_name, -(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name -from mod_sticky_post msp; +CREATE VIEW mod_sticky_post_view AS +SELECT + msp.*, + ( + SELECT + name + FROM + user_ u + WHERE + msp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + msp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_sticky_post msp; -- Recreate the view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; diff --git a/migrations/2019-10-15-181630_add_themes/down.sql b/migrations/2019-10-15-181630_add_themes/down.sql index 67a5e17bf..a31063026 100644 --- a/migrations/2019-10-15-181630_add_themes/down.sql +++ b/migrations/2019-10-15-181630_add_themes/down.sql @@ -1 +1,3 @@ -alter table user_ drop column theme; +ALTER TABLE user_ + DROP COLUMN theme; + diff --git a/migrations/2019-10-15-181630_add_themes/up.sql b/migrations/2019-10-15-181630_add_themes/up.sql index e9c3666bc..00b3d10af 100644 --- a/migrations/2019-10-15-181630_add_themes/up.sql +++ b/migrations/2019-10-15-181630_add_themes/up.sql @@ -1 +1,3 @@ -alter table user_ add column theme varchar(20) default 'darkly' not null; +ALTER TABLE user_ + ADD COLUMN theme varchar(20) DEFAULT 'darkly' NOT NULL; + diff --git a/migrations/2019-10-19-052737_create_user_mention/down.sql b/migrations/2019-10-19-052737_create_user_mention/down.sql index 7165bc86d..e21425c59 100644 --- a/migrations/2019-10-19-052737_create_user_mention/down.sql +++ b/migrations/2019-10-19-052737_create_user_mention/down.sql @@ -1,2 +1,4 @@ -drop view user_mention_view; -drop table user_mention; +DROP VIEW user_mention_view; + +DROP TABLE user_mention; + diff --git a/migrations/2019-10-19-052737_create_user_mention/up.sql b/migrations/2019-10-19-052737_create_user_mention/up.sql index 81fef0082..b02c57529 100644 --- a/migrations/2019-10-19-052737_create_user_mention/up.sql +++ b/migrations/2019-10-19-052737_create_user_mention/up.sql @@ -1,16 +1,16 @@ -create table user_mention ( - id serial primary key, - recipient_id int references user_ on update cascade on delete cascade not null, - comment_id int references comment on update cascade on delete cascade not null, - read boolean default false not null, - published timestamp not null default now(), - unique(recipient_id, comment_id) +CREATE TABLE user_mention ( + id serial PRIMARY KEY, + recipient_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + read boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (recipient_id, comment_id) ); -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -31,5 +31,9 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; + diff --git a/migrations/2019-10-21-011237_add_default_sorts/down.sql b/migrations/2019-10-21-011237_add_default_sorts/down.sql index 238c9e796..3763b5a07 100644 --- a/migrations/2019-10-21-011237_add_default_sorts/down.sql +++ b/migrations/2019-10-21-011237_add_default_sorts/down.sql @@ -1,2 +1,6 @@ -alter table user_ drop column default_sort_type; -alter table user_ drop column default_listing_type; +ALTER TABLE user_ + DROP COLUMN default_sort_type; + +ALTER TABLE user_ + DROP COLUMN default_listing_type; + diff --git a/migrations/2019-10-21-011237_add_default_sorts/up.sql b/migrations/2019-10-21-011237_add_default_sorts/up.sql index 4bb960094..62d04141e 100644 --- a/migrations/2019-10-21-011237_add_default_sorts/up.sql +++ b/migrations/2019-10-21-011237_add_default_sorts/up.sql @@ -1,2 +1,6 @@ -alter table user_ add column default_sort_type smallint default 0 not null; -alter table user_ add column default_listing_type smallint default 1 not null; +ALTER TABLE user_ + ADD COLUMN default_sort_type smallint DEFAULT 0 NOT NULL; + +ALTER TABLE user_ + ADD COLUMN default_listing_type smallint DEFAULT 1 NOT NULL; + diff --git a/migrations/2019-10-24-002614_create_password_reset_request/down.sql b/migrations/2019-10-24-002614_create_password_reset_request/down.sql index 33500dfeb..54d4ba823 100644 --- a/migrations/2019-10-24-002614_create_password_reset_request/down.sql +++ b/migrations/2019-10-24-002614_create_password_reset_request/down.sql @@ -1 +1,2 @@ -drop table password_reset_request; +DROP TABLE password_reset_request; + diff --git a/migrations/2019-10-24-002614_create_password_reset_request/up.sql b/migrations/2019-10-24-002614_create_password_reset_request/up.sql index 15cfaa593..f883d1503 100644 --- a/migrations/2019-10-24-002614_create_password_reset_request/up.sql +++ b/migrations/2019-10-24-002614_create_password_reset_request/up.sql @@ -1,6 +1,7 @@ -create table password_reset_request ( - id serial primary key, - user_id int references user_ on update cascade on delete cascade not null, - token_encrypted text not null, - published timestamp not null default now() +CREATE TABLE password_reset_request ( + id serial PRIMARY KEY, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + token_encrypted text NOT NULL, + published timestamp NOT NULL DEFAULT now() ); + diff --git a/migrations/2019-12-09-060754_add_lang/down.sql b/migrations/2019-12-09-060754_add_lang/down.sql index c13355999..eb64acf8d 100644 --- a/migrations/2019-12-09-060754_add_lang/down.sql +++ b/migrations/2019-12-09-060754_add_lang/down.sql @@ -1 +1,3 @@ -alter table user_ drop column lang; +ALTER TABLE user_ + DROP COLUMN lang; + diff --git a/migrations/2019-12-09-060754_add_lang/up.sql b/migrations/2019-12-09-060754_add_lang/up.sql index 98a72ad90..a1279da63 100644 --- a/migrations/2019-12-09-060754_add_lang/up.sql +++ b/migrations/2019-12-09-060754_add_lang/up.sql @@ -1 +1,3 @@ -alter table user_ add column lang varchar(20) default 'browser' not null; +ALTER TABLE user_ + ADD COLUMN lang varchar(20) DEFAULT 'browser' NOT NULL; + diff --git a/migrations/2019-12-11-181820_add_site_fields/down.sql b/migrations/2019-12-11-181820_add_site_fields/down.sql index 72eedba45..107d22563 100644 --- a/migrations/2019-12-11-181820_add_site_fields/down.sql +++ b/migrations/2019-12-11-181820_add_site_fields/down.sql @@ -1,16 +1,46 @@ -- Drop the columns -drop view site_view; -alter table site drop column enable_downvotes; -alter table site drop column open_registration; -alter table site drop column enable_nsfw; +DROP VIEW site_view; + +ALTER TABLE site + DROP COLUMN enable_downvotes; + +ALTER TABLE site + DROP COLUMN open_registration; + +ALTER TABLE site + DROP COLUMN enable_nsfw; -- Rebuild the views +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; diff --git a/migrations/2019-12-11-181820_add_site_fields/up.sql b/migrations/2019-12-11-181820_add_site_fields/up.sql index e107b1ac3..319aca2dd 100644 --- a/migrations/2019-12-11-181820_add_site_fields/up.sql +++ b/migrations/2019-12-11-181820_add_site_fields/up.sql @@ -1,16 +1,46 @@ -- Add the column -alter table site add column enable_downvotes boolean default true not null; -alter table site add column open_registration boolean default true not null; -alter table site add column enable_nsfw boolean default true not null; +ALTER TABLE site + ADD COLUMN enable_downvotes boolean DEFAULT TRUE NOT NULL; + +ALTER TABLE site + ADD COLUMN open_registration boolean DEFAULT TRUE NOT NULL; + +ALTER TABLE site + ADD COLUMN enable_nsfw boolean DEFAULT TRUE NOT NULL; -- Reload the view -drop view site_view; +DROP VIEW site_view; + +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; diff --git a/migrations/2019-12-29-164820_add_avatar/down.sql b/migrations/2019-12-29-164820_add_avatar/down.sql index 74b4146d9..bd062b53b 100644 --- a/migrations/2019-12-29-164820_add_avatar/down.sql +++ b/migrations/2019-12-29-164820_add_avatar/down.sql @@ -1,169 +1,380 @@ -- the views -drop view user_mention_view; -drop view reply_view; -drop view comment_view; -drop view user_view; +DROP VIEW user_mention_view; + +DROP VIEW reply_view; + +DROP VIEW comment_view; + +DROP VIEW user_view; -- user -create view user_view as -select id, -name, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + id, + name, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -- post -- Recreate the view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) - -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- community +DROP VIEW community_view; -drop view community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- Reply and comment view -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id ) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select - ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; - -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -184,41 +395,117 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -- community tables -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view site_view; +DROP VIEW community_moderator_view; -create view community_moderator_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select name from community c where cm.community_id = c.id) as community_name -from community_moderator cm; +DROP VIEW community_follower_view; -create view community_follower_view as -select *, -(select name from user_ u where cf.user_id = u.id) as user_name, -(select name from community c where cf.community_id = c.id) as community_name -from community_follower cf; +DROP VIEW community_user_ban_view; -create view community_user_ban_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select name from community c where cm.community_id = c.id) as community_name -from community_user_ban cm; +DROP VIEW site_view; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; +CREATE VIEW community_moderator_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_moderator cm; + +CREATE VIEW community_follower_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cf.community_id = c.id) AS community_name +FROM + community_follower cf; + +CREATE VIEW community_user_ban_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_user_ban cm; + +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; + +ALTER TABLE user_ RENAME COLUMN avatar TO icon; + +ALTER TABLE user_ + ALTER COLUMN icon TYPE bytea + USING icon::bytea; -alter table user_ rename column avatar to icon; -alter table user_ alter column icon type bytea using icon::bytea; diff --git a/migrations/2019-12-29-164820_add_avatar/up.sql b/migrations/2019-12-29-164820_add_avatar/up.sql index f9265154b..79bf2cc55 100644 --- a/migrations/2019-12-29-164820_add_avatar/up.sql +++ b/migrations/2019-12-29-164820_add_avatar/up.sql @@ -1,177 +1,408 @@ -- Rename to avatar -alter table user_ rename column icon to avatar; -alter table user_ alter column avatar type text; +ALTER TABLE user_ RENAME COLUMN icon TO avatar; + +ALTER TABLE user_ + ALTER COLUMN avatar TYPE text; -- Rebuild nearly all the views, to include the creator avatars - -- user -drop view user_view; -create view user_view as -select id, -name, -avatar, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -- post -- Recreate the view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select avatar from user_ where p.creator_id = user_.id) as creator_avatar, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) - -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- community -drop view community_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select avatar from user_ u where c.creator_id = u.id) as creator_avatar, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +DROP VIEW community_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- reply and comment view -drop view reply_view; -drop view user_mention_view; -drop view comment_view; -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - (select avatar from user_ where c.creator_id = user_.id) as creator_avatar, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id +DROP VIEW reply_view; + +DROP VIEW user_mention_view; + +DROP VIEW comment_view; + +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id ) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select - ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; - -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -193,42 +424,136 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -- community views -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view site_view; +DROP VIEW community_moderator_view; -create view community_moderator_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select name from community c where cm.community_id = c.id) as community_name -from community_moderator cm; +DROP VIEW community_follower_view; -create view community_follower_view as -select *, -(select name from user_ u where cf.user_id = u.id) as user_name, -(select avatar from user_ u where cf.user_id = u.id), -(select name from community c where cf.community_id = c.id) as community_name -from community_follower cf; +DROP VIEW community_user_ban_view; -create view community_user_ban_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select name from community c where cm.community_id = c.id) as community_name -from community_user_ban cm; +DROP VIEW site_view; + +CREATE VIEW community_moderator_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_moderator cm; + +CREATE VIEW community_follower_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cf.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cf.community_id = c.id) AS community_name +FROM + community_follower cf; + +CREATE VIEW community_user_ban_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_user_ban cm; + +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_avatar, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select avatar from user_ u where s.creator_id = u.id) as creator_avatar, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; diff --git a/migrations/2020-01-01-200418_add_email_to_user_view/down.sql b/migrations/2020-01-01-200418_add_email_to_user_view/down.sql index 92f771f84..759623c72 100644 --- a/migrations/2020-01-01-200418_add_email_to_user_view/down.sql +++ b/migrations/2020-01-01-200418_add_email_to_user_view/down.sql @@ -1,15 +1,47 @@ -- user -drop view user_view; -create view user_view as -select id, -name, -avatar, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + diff --git a/migrations/2020-01-01-200418_add_email_to_user_view/up.sql b/migrations/2020-01-01-200418_add_email_to_user_view/up.sql index 59972dfb8..d1a319e7a 100644 --- a/migrations/2020-01-01-200418_add_email_to_user_view/up.sql +++ b/migrations/2020-01-01-200418_add_email_to_user_view/up.sql @@ -1,16 +1,48 @@ -- user -drop view user_view; -create view user_view as -select id, -name, -avatar, -email, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + email, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + diff --git a/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/down.sql b/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/down.sql index ec061223d..517e2b30b 100644 --- a/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/down.sql +++ b/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/down.sql @@ -1,20 +1,55 @@ -- Drop the columns -drop view user_view; -alter table user_ drop column show_avatars; -alter table user_ drop column send_notifications_to_email; +DROP VIEW user_view; + +ALTER TABLE user_ + DROP COLUMN show_avatars; + +ALTER TABLE user_ + DROP COLUMN send_notifications_to_email; -- Rebuild the view -create view user_view as -select id, -name, -avatar, -email, -fedi_name, -admin, -banned, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + email, + fedi_name, + admin, + banned, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + diff --git a/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/up.sql b/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/up.sql index 21f0aff49..661907d26 100644 --- a/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/up.sql +++ b/migrations/2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/up.sql @@ -1,22 +1,57 @@ -- Add columns -alter table user_ add column show_avatars boolean default true not null; -alter table user_ add column send_notifications_to_email boolean default false not null; +ALTER TABLE user_ + ADD COLUMN show_avatars boolean DEFAULT TRUE NOT NULL; + +ALTER TABLE user_ + ADD COLUMN send_notifications_to_email boolean DEFAULT FALSE NOT NULL; -- Rebuild the user_view -drop view user_view; -create view user_view as -select id, -name, -avatar, -email, -fedi_name, -admin, -banned, -show_avatars, -send_notifications_to_email, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + email, + fedi_name, + admin, + banned, + show_avatars, + send_notifications_to_email, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + diff --git a/migrations/2020-01-11-012452_add_indexes/down.sql b/migrations/2020-01-11-012452_add_indexes/down.sql index ad674c50b..b6e9b25b5 100644 --- a/migrations/2020-01-11-012452_add_indexes/down.sql +++ b/migrations/2020-01-11-012452_add_indexes/down.sql @@ -1,16 +1,24 @@ -drop index idx_post_creator; -drop index idx_post_community; +DROP INDEX idx_post_creator; -drop index idx_post_like_post; -drop index idx_post_like_user; +DROP INDEX idx_post_community; -drop index idx_comment_creator; -drop index idx_comment_parent; -drop index idx_comment_post; +DROP INDEX idx_post_like_post; -drop index idx_comment_like_comment; -drop index idx_comment_like_user; -drop index idx_comment_like_post; +DROP INDEX idx_post_like_user; + +DROP INDEX idx_comment_creator; + +DROP INDEX idx_comment_parent; + +DROP INDEX idx_comment_post; + +DROP INDEX idx_comment_like_comment; + +DROP INDEX idx_comment_like_user; + +DROP INDEX idx_comment_like_post; + +DROP INDEX idx_community_creator; + +DROP INDEX idx_community_category; -drop index idx_community_creator; -drop index idx_community_category; diff --git a/migrations/2020-01-11-012452_add_indexes/up.sql b/migrations/2020-01-11-012452_add_indexes/up.sql index 911f0875b..896e2addd 100644 --- a/migrations/2020-01-11-012452_add_indexes/up.sql +++ b/migrations/2020-01-11-012452_add_indexes/up.sql @@ -1,17 +1,25 @@ -- Go through all the tables joins, optimize every view, CTE, etc. -create index idx_post_creator on post (creator_id); -create index idx_post_community on post (community_id); +CREATE INDEX idx_post_creator ON post (creator_id); -create index idx_post_like_post on post_like (post_id); -create index idx_post_like_user on post_like (user_id); +CREATE INDEX idx_post_community ON post (community_id); -create index idx_comment_creator on comment (creator_id); -create index idx_comment_parent on comment (parent_id); -create index idx_comment_post on comment (post_id); +CREATE INDEX idx_post_like_post ON post_like (post_id); -create index idx_comment_like_comment on comment_like (comment_id); -create index idx_comment_like_user on comment_like (user_id); -create index idx_comment_like_post on comment_like (post_id); +CREATE INDEX idx_post_like_user ON post_like (user_id); + +CREATE INDEX idx_comment_creator ON comment (creator_id); + +CREATE INDEX idx_comment_parent ON comment (parent_id); + +CREATE INDEX idx_comment_post ON comment (post_id); + +CREATE INDEX idx_comment_like_comment ON comment_like (comment_id); + +CREATE INDEX idx_comment_like_user ON comment_like (user_id); + +CREATE INDEX idx_comment_like_post ON comment_like (post_id); + +CREATE INDEX idx_community_creator ON community (creator_id); + +CREATE INDEX idx_community_category ON community (category_id); -create index idx_community_creator on community (creator_id); -create index idx_community_category on community (category_id); diff --git a/migrations/2020-01-13-025151_create_materialized_views/down.sql b/migrations/2020-01-13-025151_create_materialized_views/down.sql index 39985ab55..778e483cb 100644 --- a/migrations/2020-01-13-025151_create_materialized_views/down.sql +++ b/migrations/2020-01-13-025151_create_materialized_views/down.sql @@ -1,202 +1,457 @@ -- functions and triggers -drop trigger refresh_user on user_; -drop function refresh_user(); -drop trigger refresh_post on post; -drop function refresh_post(); -drop trigger refresh_post_like on post_like; -drop function refresh_post_like(); -drop trigger refresh_community on community; -drop function refresh_community(); -drop trigger refresh_community_follower on community_follower; -drop function refresh_community_follower(); -drop trigger refresh_community_user_ban on community_user_ban; -drop function refresh_community_user_ban(); -drop trigger refresh_comment on comment; -drop function refresh_comment(); -drop trigger refresh_comment_like on comment_like; -drop function refresh_comment_like(); +DROP TRIGGER refresh_user ON user_; + +DROP FUNCTION refresh_user (); + +DROP TRIGGER refresh_post ON post; + +DROP FUNCTION refresh_post (); + +DROP TRIGGER refresh_post_like ON post_like; + +DROP FUNCTION refresh_post_like (); + +DROP TRIGGER refresh_community ON community; + +DROP FUNCTION refresh_community (); + +DROP TRIGGER refresh_community_follower ON community_follower; + +DROP FUNCTION refresh_community_follower (); + +DROP TRIGGER refresh_community_user_ban ON community_user_ban; + +DROP FUNCTION refresh_community_user_ban (); + +DROP TRIGGER refresh_comment ON comment; + +DROP FUNCTION refresh_comment (); + +DROP TRIGGER refresh_comment_like ON comment_like; + +DROP FUNCTION refresh_comment_like (); -- post -- Recreate the view -drop view post_view; -create view post_view as -with all_post as -( - select - p.*, - (select u.banned from user_ u where p.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where p.creator_id = user_.id) as creator_name, - (select avatar from user_ where p.creator_id = user_.id) as creator_avatar, - (select name from community where p.community_id = community.id) as community_name, - (select removed from community c where p.community_id = c.id) as community_removed, - (select deleted from community c where p.community_id = c.id) as community_deleted, - (select nsfw from community c where p.community_id = c.id) as community_nsfw, - (select count(*) from comment where comment.post_id = p.id) as number_of_comments, - coalesce(sum(pl.score), 0) as score, - count (case when pl.score = 1 then 1 else null end) as upvotes, - count (case when pl.score = -1 then 1 else null end) as downvotes, - hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank - from post p - left join post_like pl on p.id = pl.post_id - group by p.id +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.id ) +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +DROP VIEW post_mview; -union all +DROP MATERIALIZED VIEW post_aggregates_mview; -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_aggregates_view; -- user -drop materialized view user_mview; -drop view user_view; -create view user_view as -select id, -name, -avatar, -email, -fedi_name, -admin, -banned, -show_avatars, -send_notifications_to_email, -published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP MATERIALIZED VIEW user_mview; + +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + id, + name, + avatar, + email, + fedi_name, + admin, + banned, + show_avatars, + send_notifications_to_email, + published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -- community -drop view community_mview; -drop materialized view community_aggregates_mview; -drop view community_view; -drop view community_aggregates_view; -create view community_view as -with all_community as -( - select *, - (select name from user_ u where c.creator_id = u.id) as creator_name, - (select avatar from user_ u where c.creator_id = u.id) as creator_avatar, - (select name from category ct where c.category_id = ct.id) as category_name, - (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, - (select count(*) from post p where p.community_id = c.id) as number_of_posts, - (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, - hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank - from community c +DROP VIEW community_mview; + +DROP MATERIALIZED VIEW community_aggregates_mview; + +DROP VIEW community_view; + +DROP VIEW community_aggregates_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- reply and comment view -drop view reply_view; -drop view user_mention_view; -drop view comment_view; -drop view comment_mview; -drop materialized view comment_aggregates_mview; -drop view comment_aggregates_view; -create view comment_view as -with all_comment as -( - select - c.*, - (select community_id from post p where p.id = c.post_id), - (select u.banned from user_ u where c.creator_id = u.id) as banned, - (select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, - (select name from user_ where c.creator_id = user_.id) as creator_name, - (select avatar from user_ where c.creator_id = user_.id) as creator_avatar, - coalesce(sum(cl.score), 0) as score, - count (case when cl.score = 1 then 1 else null end) as upvotes, - count (case when cl.score = -1 then 1 else null end) as downvotes - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.id +DROP VIEW reply_view; + +DROP VIEW user_mention_view; + +DROP VIEW comment_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.id ) + SELECT + ac.*, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select - ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; - -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -218,6 +473,9 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; diff --git a/migrations/2020-01-13-025151_create_materialized_views/up.sql b/migrations/2020-01-13-025151_create_materialized_views/up.sql index e0f206d34..47fc5e0f8 100644 --- a/migrations/2020-01-13-025151_create_materialized_views/up.sql +++ b/migrations/2020-01-13-025151_create_materialized_views/up.sql @@ -1,285 +1,565 @@ -- post -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank -from post p -left join post_like pl on p.id = pl.post_id -group by p.id; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id +GROUP BY + p.id; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -drop view post_view; -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +DROP VIEW post_view; + +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- user_view -drop view user_view; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.fedi_name, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view; -create materialized view user_mview as select * from user_view; +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.fedi_name, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create unique index idx_user_mview_id on user_mview (id); +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; + +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- community -create view community_aggregates_view as -select c.*, -(select name from user_ u where c.creator_id = u.id) as creator_name, -(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, -(select name from category ct where c.category_id = ct.id) as category_name, -(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, -(select count(*) from post p where p.community_id = c.id) as number_of_posts, -(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, -hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank -from community c; +CREATE VIEW community_aggregates_view AS +SELECT + c.*, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c; -create materialized view community_aggregates_mview as select * from community_aggregates_view; +CREATE MATERIALIZED VIEW community_aggregates_mview AS +SELECT + * +FROM + community_aggregates_view; -create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); +CREATE UNIQUE INDEX idx_community_aggregates_mview_id ON community_aggregates_mview (id); -drop view community_view; -create view community_view as -with all_community as -( - select - ca.* - from community_aggregates_view ca +DROP VIEW community_view; + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_view ca ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -create view community_mview as -with all_community as -( - select - ca.* - from community_aggregates_mview ca +CREATE VIEW community_mview AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -drop view reply_view; -drop view user_mention_view; -drop view comment_view; +DROP VIEW reply_view; -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +DROP VIEW user_mention_view; + +DROP VIEW comment_view; + +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -301,137 +581,150 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -- user -create or replace function refresh_user() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently user_mview; - refresh materialized view concurrently comment_aggregates_mview; -- cause of bans - refresh materialized view concurrently post_aggregates_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY comment_aggregates_mview; + -- cause of bans + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + RETURN NULL; +END +$$; -create trigger refresh_user -after insert or update or delete or truncate -on user_ -for each statement -execute procedure refresh_user(); +CREATE TRIGGER refresh_user + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON user_ + FOR EACH statement + EXECUTE PROCEDURE refresh_user (); -- post -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; -create trigger refresh_post -after insert or update or delete or truncate -on post -for each statement -execute procedure refresh_post(); +CREATE TRIGGER refresh_post + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON post + FOR EACH statement + EXECUTE PROCEDURE refresh_post (); -- post_like -create or replace function refresh_post_like() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_post_like () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; -create trigger refresh_post_like -after insert or update or delete or truncate -on post_like -for each statement -execute procedure refresh_post_like(); +CREATE TRIGGER refresh_post_like + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON post_like + FOR EACH statement + EXECUTE PROCEDURE refresh_post_like (); -- community -create or replace function refresh_community() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently community_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY community_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; -create trigger refresh_community -after insert or update or delete or truncate -on community -for each statement -execute procedure refresh_community(); +CREATE TRIGGER refresh_community + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON community + FOR EACH statement + EXECUTE PROCEDURE refresh_community (); -- community_follower -create or replace function refresh_community_follower() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently community_aggregates_mview; - refresh materialized view concurrently post_aggregates_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_community_follower () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY community_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + RETURN NULL; +END +$$; -create trigger refresh_community_follower -after insert or update or delete or truncate -on community_follower -for each statement -execute procedure refresh_community_follower(); +CREATE TRIGGER refresh_community_follower + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON community_follower + FOR EACH statement + EXECUTE PROCEDURE refresh_community_follower (); -- community_user_ban -create or replace function refresh_community_user_ban() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently comment_aggregates_mview; - refresh materialized view concurrently post_aggregates_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_community_user_ban () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY comment_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + RETURN NULL; +END +$$; -create trigger refresh_community_user_ban -after insert or update or delete or truncate -on community_user_ban -for each statement -execute procedure refresh_community_user_ban(); +CREATE TRIGGER refresh_community_user_ban + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON community_user_ban + FOR EACH statement + EXECUTE PROCEDURE refresh_community_user_ban (); -- comment -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently comment_aggregates_mview; - refresh materialized view concurrently community_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY comment_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY community_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; -create trigger refresh_comment -after insert or update or delete or truncate -on comment -for each statement -execute procedure refresh_comment(); +CREATE TRIGGER refresh_comment + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON comment + FOR EACH statement + EXECUTE PROCEDURE refresh_comment (); -- comment_like -create or replace function refresh_comment_like() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently comment_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_comment_like () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY comment_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; + +CREATE TRIGGER refresh_comment_like + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON comment_like + FOR EACH statement + EXECUTE PROCEDURE refresh_comment_like (); -create trigger refresh_comment_like -after insert or update or delete or truncate -on comment_like -for each statement -execute procedure refresh_comment_like(); diff --git a/migrations/2020-01-21-001001_create_private_message/down.sql b/migrations/2020-01-21-001001_create_private_message/down.sql index 0d951e3ea..9b55f39ec 100644 --- a/migrations/2020-01-21-001001_create_private_message/down.sql +++ b/migrations/2020-01-21-001001_create_private_message/down.sql @@ -1,34 +1,72 @@ -- Drop the triggers -drop trigger refresh_private_message on private_message; -drop function refresh_private_message(); +DROP TRIGGER refresh_private_message ON private_message; + +DROP FUNCTION refresh_private_message (); -- Drop the view and table -drop view private_message_view cascade; -drop table private_message; +DROP VIEW private_message_view CASCADE; + +DROP TABLE private_message; -- Rebuild the old views -drop view user_view cascade; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.fedi_name, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view CASCADE; -create materialized view user_mview as select * from user_view; +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.fedi_name, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create unique index idx_user_mview_id on user_mview (id); +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; + +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- Drop the columns -alter table user_ drop column matrix_user_id; +ALTER TABLE user_ + DROP COLUMN matrix_user_id; + diff --git a/migrations/2020-01-21-001001_create_private_message/up.sql b/migrations/2020-01-21-001001_create_private_message/up.sql index 48e16dd83..cb19eb42b 100644 --- a/migrations/2020-01-21-001001_create_private_message/up.sql +++ b/migrations/2020-01-21-001001_create_private_message/up.sql @@ -1,76 +1,117 @@ -- Creating private message -create table private_message ( - id serial primary key, - creator_id int references user_ on update cascade on delete cascade not null, - recipient_id int references user_ on update cascade on delete cascade not null, - content text not null, - deleted boolean default false not null, - read boolean default false not null, - published timestamp not null default now(), - updated timestamp +CREATE TABLE private_message ( + id serial PRIMARY KEY, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + recipient_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + content text NOT NULL, + deleted boolean DEFAULT FALSE NOT NULL, + read boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); -- Create the view and materialized view which has the avatar and creator name -create view private_message_view as -select -pm.*, -u.name as creator_name, -u.avatar as creator_avatar, -u2.name as recipient_name, -u2.avatar as recipient_avatar -from private_message pm -inner join user_ u on u.id = pm.creator_id -inner join user_ u2 on u2.id = pm.recipient_id; +CREATE VIEW private_message_view AS +SELECT + pm.*, + u.name AS creator_name, + u.avatar AS creator_avatar, + u2.name AS recipient_name, + u2.avatar AS recipient_avatar +FROM + private_message pm + INNER JOIN user_ u ON u.id = pm.creator_id + INNER JOIN user_ u2 ON u2.id = pm.recipient_id; -create materialized view private_message_mview as select * from private_message_view; +CREATE MATERIALIZED VIEW private_message_mview AS +SELECT + * +FROM + private_message_view; -create unique index idx_private_message_mview_id on private_message_mview (id); +CREATE UNIQUE INDEX idx_private_message_mview_id ON private_message_mview (id); -- Create the triggers -create or replace function refresh_private_message() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently private_message_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_private_message () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY private_message_mview; + RETURN NULL; +END +$$; -create trigger refresh_private_message -after insert or update or delete or truncate -on private_message -for each statement -execute procedure refresh_private_message(); +CREATE TRIGGER refresh_private_message + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON private_message + FOR EACH statement + EXECUTE PROCEDURE refresh_private_message (); -- Update user to include matrix id -alter table user_ add column matrix_user_id text unique; +ALTER TABLE user_ + ADD COLUMN matrix_user_id text UNIQUE; -drop view user_view cascade; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.fedi_name, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +DROP VIEW user_view CASCADE; -create materialized view user_mview as select * from user_view; +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.fedi_name, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create unique index idx_user_mview_id on user_mview (id); +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; + +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- This is what a group pm table would look like -- Not going to do it now because of the complications --- +-- -- create table private_message ( -- id serial primary key, -- creator_id int references user_ on update cascade on delete cascade not null, @@ -79,7 +120,7 @@ create unique index idx_user_mview_id on user_mview (id); -- published timestamp not null default now(), -- updated timestamp -- ); --- +-- -- create table private_message_recipient ( -- id serial primary key, -- private_message_id int references private_message on update cascade on delete cascade not null, diff --git a/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql b/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql index 06ec5971f..ae32a42e5 100644 --- a/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql +++ b/migrations/2020-01-29-011901_create_reply_materialized_view/down.sql @@ -1,25 +1,37 @@ -- Drop the materialized / built views -drop view reply_view; -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +DROP VIEW reply_view; + +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_view cv, + closereply +WHERE + closereply.id = cv.id; + diff --git a/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql b/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql index ebbb1dff4..f6a291d27 100644 --- a/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql +++ b/migrations/2020-01-29-011901_create_reply_materialized_view/up.sql @@ -1,27 +1,38 @@ -- https://github.com/dessalines/lemmy/issues/197 -drop view reply_view; +DROP VIEW reply_view; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; + diff --git a/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql b/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql index d93ebc2ed..99d0856cf 100644 --- a/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql +++ b/migrations/2020-01-29-030825_create_user_mention_materialized_view/down.sql @@ -1 +1,2 @@ -drop view user_mention_mview; +DROP VIEW user_mention_mview; + diff --git a/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql b/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql index b0ae4e9d9..0130f3268 100644 --- a/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql +++ b/migrations/2020-01-29-030825_create_user_mention_materialized_view/up.sql @@ -1,14 +1,13 @@ -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -26,20 +25,27 @@ select ac.score, ac.upvotes, ac.downvotes, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -57,11 +63,11 @@ select ac.score, ac.upvotes, ac.downvotes, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-02-02-004806_add_case_insensitive_usernames/down.sql b/migrations/2020-02-02-004806_add_case_insensitive_usernames/down.sql index 0c6f112f0..d7452a000 100644 --- a/migrations/2020-02-02-004806_add_case_insensitive_usernames/down.sql +++ b/migrations/2020-02-02-004806_add_case_insensitive_usernames/down.sql @@ -1,2 +1,4 @@ -drop index idx_user_name_lower; -drop index idx_user_email_lower; +DROP INDEX idx_user_name_lower; + +DROP INDEX idx_user_email_lower; + diff --git a/migrations/2020-02-02-004806_add_case_insensitive_usernames/up.sql b/migrations/2020-02-02-004806_add_case_insensitive_usernames/up.sql index 07f854b1c..5cf7e0490 100644 --- a/migrations/2020-02-02-004806_add_case_insensitive_usernames/up.sql +++ b/migrations/2020-02-02-004806_add_case_insensitive_usernames/up.sql @@ -1,5 +1,4 @@ -- Add case insensitive username and email uniqueness - -- An example of showing the dupes: -- select -- max(id) as id, @@ -8,22 +7,28 @@ -- from user_ -- group by lower(name) -- having count(*) > 1; - -- Delete username dupes, keeping the first one -delete -from user_ -where id not in ( - select min(id) - from user_ - group by lower(name), lower(fedi_name) -); +DELETE FROM user_ +WHERE id NOT IN ( + SELECT + min(id) + FROM + user_ + GROUP BY + lower(name), + lower(fedi_name)); --- The user index -create unique index idx_user_name_lower on user_ (lower(name)); +-- The user index +CREATE UNIQUE INDEX idx_user_name_lower ON user_ (lower(name)); -- Email lower -create unique index idx_user_email_lower on user_ (lower(email)); +CREATE UNIQUE INDEX idx_user_email_lower ON user_ (lower(email)); -- Set empty emails properly to null -update user_ set email = null where email = ''; +UPDATE + user_ +SET + email = NULL +WHERE + email = ''; diff --git a/migrations/2020-02-06-165953_change_post_title_length/down.sql b/migrations/2020-02-06-165953_change_post_title_length/down.sql index 2bc765f85..19a5c37e8 100644 --- a/migrations/2020-02-06-165953_change_post_title_length/down.sql +++ b/migrations/2020-02-06-165953_change_post_title_length/down.sql @@ -1,132 +1,409 @@ -- Drop the dependent views -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; -drop view mod_remove_post_view; -drop view mod_sticky_post_view; -drop view mod_lock_post_view; -drop view mod_remove_comment_view; +DROP VIEW post_view; -alter table post alter column name type varchar(100); +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; + +DROP VIEW mod_remove_post_view; + +DROP VIEW mod_sticky_post_view; + +DROP VIEW mod_lock_post_view; + +DROP VIEW mod_remove_comment_view; + +ALTER TABLE post + ALTER COLUMN name TYPE varchar(100); -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank -from post p -left join post_like pl on p.id = pl.post_id -group by p.id; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id +GROUP BY + p.id; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- The mod views +CREATE VIEW mod_remove_post_view AS +SELECT + mrp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mrp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_remove_post mrp; -create view mod_remove_post_view as -select mrp.*, -(select name from user_ u where mrp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mrp.post_id = p.id) as post_name, -(select c.id from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_name -from mod_remove_post mrp; +CREATE VIEW mod_lock_post_view AS +SELECT + mlp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mlp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mlp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_lock_post mlp; -create view mod_lock_post_view as -select mlp.*, -(select name from user_ u where mlp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mlp.post_id = p.id) as post_name, -(select c.id from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_name -from mod_lock_post mlp; +CREATE VIEW mod_remove_comment_view AS +SELECT + mrc.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrc.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + c.id + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_user_id, + ( + SELECT + name + FROM + user_ u, + comment c + WHERE + mrc.comment_id = c.id + AND u.id = c.creator_id) AS comment_user_name, + ( + SELECT + content + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_content, + ( + SELECT + p.id + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_id, + ( + SELECT + p.name + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_name, + ( + SELECT + co.id + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_id, + ( + SELECT + co.name + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_name +FROM + mod_remove_comment mrc; -create view mod_remove_comment_view as -select mrc.*, -(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name, -(select c.id from comment c where mrc.comment_id = c.id) as comment_user_id, -(select name from user_ u, comment c where mrc.comment_id = c.id and u.id = c.creator_id) as comment_user_name, -(select content from comment c where mrc.comment_id = c.id) as comment_content, -(select p.id from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_id, -(select p.name from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_name, -(select co.id from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_id, -(select co.name from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_name -from mod_remove_comment mrc; +CREATE VIEW mod_sticky_post_view AS +SELECT + msp.*, + ( + SELECT + name + FROM + user_ u + WHERE + msp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + msp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_sticky_post msp; -create view mod_sticky_post_view as -select msp.*, -(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name, -(select name from post p where msp.post_id = p.id) as post_name, -(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name -from mod_sticky_post msp; diff --git a/migrations/2020-02-06-165953_change_post_title_length/up.sql b/migrations/2020-02-06-165953_change_post_title_length/up.sql index 006a7d049..b0ed7254b 100644 --- a/migrations/2020-02-06-165953_change_post_title_length/up.sql +++ b/migrations/2020-02-06-165953_change_post_title_length/up.sql @@ -1,133 +1,410 @@ -- Drop the dependent views -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; -drop view mod_remove_post_view; -drop view mod_sticky_post_view; -drop view mod_lock_post_view; -drop view mod_remove_comment_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; + +DROP VIEW mod_remove_post_view; + +DROP VIEW mod_sticky_post_view; + +DROP VIEW mod_lock_post_view; + +DROP VIEW mod_remove_comment_view; -- Add the extra post limit -alter table post alter column name type varchar(200); +ALTER TABLE post + ALTER COLUMN name TYPE varchar(200); -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank -from post p -left join post_like pl on p.id = pl.post_id -group by p.id; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id +GROUP BY + p.id; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- The mod views +CREATE VIEW mod_remove_post_view AS +SELECT + mrp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mrp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mrp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_remove_post mrp; -create view mod_remove_post_view as -select mrp.*, -(select name from user_ u where mrp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mrp.post_id = p.id) as post_name, -(select c.id from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_name -from mod_remove_post mrp; +CREATE VIEW mod_lock_post_view AS +SELECT + mlp.*, + ( + SELECT + name + FROM + user_ u + WHERE + mlp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + mlp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + mlp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_lock_post mlp; -create view mod_lock_post_view as -select mlp.*, -(select name from user_ u where mlp.mod_user_id = u.id) as mod_user_name, -(select name from post p where mlp.post_id = p.id) as post_name, -(select c.id from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_name -from mod_lock_post mlp; +CREATE VIEW mod_remove_comment_view AS +SELECT + mrc.*, + ( + SELECT + name + FROM + user_ u + WHERE + mrc.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + c.id + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_user_id, + ( + SELECT + name + FROM + user_ u, + comment c + WHERE + mrc.comment_id = c.id + AND u.id = c.creator_id) AS comment_user_name, + ( + SELECT + content + FROM + comment c + WHERE + mrc.comment_id = c.id) AS comment_content, + ( + SELECT + p.id + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_id, + ( + SELECT + p.name + FROM + post p, + comment c + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id) AS post_name, + ( + SELECT + co.id + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_id, + ( + SELECT + co.name + FROM + comment c, + post p, + community co + WHERE + mrc.comment_id = c.id + AND c.post_id = p.id + AND p.community_id = co.id) AS community_name +FROM + mod_remove_comment mrc; -create view mod_remove_comment_view as -select mrc.*, -(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name, -(select c.id from comment c where mrc.comment_id = c.id) as comment_user_id, -(select name from user_ u, comment c where mrc.comment_id = c.id and u.id = c.creator_id) as comment_user_name, -(select content from comment c where mrc.comment_id = c.id) as comment_content, -(select p.id from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_id, -(select p.name from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_name, -(select co.id from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_id, -(select co.name from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_name -from mod_remove_comment mrc; +CREATE VIEW mod_sticky_post_view AS +SELECT + msp.*, + ( + SELECT + name + FROM + user_ u + WHERE + msp.mod_user_id = u.id) AS mod_user_name, + ( + SELECT + name + FROM + post p + WHERE + msp.post_id = p.id) AS post_name, + ( + SELECT + c.id + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_id, + ( + SELECT + c.name + FROM + post p, + community c + WHERE + msp.post_id = p.id + AND p.community_id = c.id) AS community_name +FROM + mod_sticky_post msp; -create view mod_sticky_post_view as -select msp.*, -(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name, -(select name from post p where msp.post_id = p.id) as post_name, -(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id, -(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name -from mod_sticky_post msp; diff --git a/migrations/2020-02-07-210055_add_comment_subscribed/down.sql b/migrations/2020-02-07-210055_add_comment_subscribed/down.sql index b6120d151..56edcaea3 100644 --- a/migrations/2020-02-07-210055_add_comment_subscribed/down.sql +++ b/migrations/2020-02-07-210055_add_comment_subscribed/down.sql @@ -1,117 +1,191 @@ +DROP VIEW reply_view; -drop view reply_view; -drop view user_mention_view; -drop view user_mention_mview; -drop view comment_view; -drop view comment_mview; -drop materialized view comment_aggregates_mview; -drop view comment_aggregates_view; +DROP VIEW user_mention_view; + +DROP VIEW user_mention_mview; + +DROP VIEW comment_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP VIEW comment_aggregates_view; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as saved -from all_comment ac -; - + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved + FROM + all_comment ac; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -133,21 +207,22 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; - -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -165,20 +240,27 @@ select ac.score, ac.upvotes, ac.downvotes, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -196,11 +278,11 @@ select ac.score, ac.upvotes, ac.downvotes, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-02-07-210055_add_comment_subscribed/up.sql b/migrations/2020-02-07-210055_add_comment_subscribed/up.sql index 8836a571a..bdff8c1da 100644 --- a/migrations/2020-02-07-210055_add_comment_subscribed/up.sql +++ b/migrations/2020-02-07-210055_add_comment_subscribed/up.sql @@ -1,125 +1,221 @@ - -- Adding community name, hot_rank, to comment_view, user_mention_view, and subscribed to comment_view - -- Rebuild the comment view -drop view reply_view; -drop view user_mention_view; -drop view user_mention_mview; -drop view comment_view; -drop view comment_mview; -drop materialized view comment_aggregates_mview; -drop view comment_aggregates_view; +DROP VIEW reply_view; + +DROP VIEW user_mention_view; + +DROP VIEW user_mention_mview; + +DROP VIEW comment_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP VIEW comment_aggregates_view; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + co.name + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_name, + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(cl.score), 0), c.published) AS hot_rank +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -143,21 +239,22 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; - -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -177,20 +274,27 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -210,11 +314,11 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql b/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql index 8b912fa36..3bf7bfc55 100644 --- a/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql +++ b/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql @@ -1,88 +1,206 @@ -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank -from post p -left join post_like pl on p.id = pl.post_id -group by p.id; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), p.published) AS hot_rank +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id +GROUP BY + p.id; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; diff --git a/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql b/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql index e15412771..a02406574 100644 --- a/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql +++ b/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql @@ -1,106 +1,227 @@ -- Adds a newest_activity_time for the post_views, in order to sort by newest comment -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; diff --git a/migrations/2020-03-06-202329_add_post_iframely_data/down.sql b/migrations/2020-03-06-202329_add_post_iframely_data/down.sql index 71dcc6bab..08a993539 100644 --- a/migrations/2020-03-06-202329_add_post_iframely_data/down.sql +++ b/migrations/2020-03-06-202329_add_post_iframely_data/down.sql @@ -1,112 +1,240 @@ -- Adds a newest_activity_time for the post_views, in order to sort by newest comment -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- Drop the columns -alter table post drop column embed_title; -alter table post drop column embed_description; -alter table post drop column embed_html; -alter table post drop column thumbnail_url; +ALTER TABLE post + DROP COLUMN embed_title; + +ALTER TABLE post + DROP COLUMN embed_description; + +ALTER TABLE post + DROP COLUMN embed_html; + +ALTER TABLE post + DROP COLUMN thumbnail_url; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; diff --git a/migrations/2020-03-06-202329_add_post_iframely_data/up.sql b/migrations/2020-03-06-202329_add_post_iframely_data/up.sql index d431bb7fa..c0d372dbf 100644 --- a/migrations/2020-03-06-202329_add_post_iframely_data/up.sql +++ b/migrations/2020-03-06-202329_add_post_iframely_data/up.sql @@ -1,115 +1,241 @@ -- Add the columns -alter table post add column embed_title text; -alter table post add column embed_description text; -alter table post add column embed_html text; -alter table post add column thumbnail_url text; +ALTER TABLE post + ADD COLUMN embed_title text; + +ALTER TABLE post + ADD COLUMN embed_description text; + +ALTER TABLE post + ADD COLUMN embed_html text; + +ALTER TABLE post + ADD COLUMN thumbnail_url text; -- Regenerate the views - -- Adds a newest_activity_time for the post_views, in order to sort by newest comment -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; diff --git a/migrations/2020-03-26-192410_add_activitypub_tables/down.sql b/migrations/2020-03-26-192410_add_activitypub_tables/down.sql index b1710623e..27963d857 100644 --- a/migrations/2020-03-26-192410_add_activitypub_tables/down.sql +++ b/migrations/2020-03-26-192410_add_activitypub_tables/down.sql @@ -1,16 +1,17 @@ -drop table activity; +DROP TABLE activity; -alter table user_ -drop column actor_id, -drop column private_key, -drop column public_key, -drop column bio, -drop column local, -drop column last_refreshed_at; +ALTER TABLE user_ + DROP COLUMN actor_id, + DROP COLUMN private_key, + DROP COLUMN public_key, + DROP COLUMN bio, + DROP COLUMN local, + DROP COLUMN last_refreshed_at; + +ALTER TABLE community + DROP COLUMN actor_id, + DROP COLUMN private_key, + DROP COLUMN public_key, + DROP COLUMN local, + DROP COLUMN last_refreshed_at; -alter table community -drop column actor_id, -drop column private_key, -drop column public_key, -drop column local, -drop column last_refreshed_at; diff --git a/migrations/2020-03-26-192410_add_activitypub_tables/up.sql b/migrations/2020-03-26-192410_add_activitypub_tables/up.sql index 06db580e8..1359fa494 100644 --- a/migrations/2020-03-26-192410_add_activitypub_tables/up.sql +++ b/migrations/2020-03-26-192410_add_activitypub_tables/up.sql @@ -1,36 +1,35 @@ -- The Activitypub activity table -- All user actions must create a row here. -create table activity ( - id serial primary key, - user_id int references user_ on update cascade on delete cascade not null, -- Ensures that the user is set up here. - data jsonb not null, - local boolean not null default true, - published timestamp not null default now(), - updated timestamp +CREATE TABLE activity ( + id serial PRIMARY KEY, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- Ensures that the user is set up here. + data jsonb NOT NULL, + local boolean NOT NULL DEFAULT TRUE, + published timestamp NOT NULL DEFAULT now(), + updated timestamp ); -- Making sure that id is unique -create unique index idx_activity_unique_apid on activity ((data ->> 'id'::text)); +CREATE UNIQUE INDEX idx_activity_unique_apid ON activity ((data ->> 'id'::text)); -- Add federation columns to the two actor tables -alter table user_ +ALTER TABLE user_ -- TODO uniqueness constraints should be added on these 3 columns later -add column actor_id character varying(255) not null default 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local -add column bio text, -- not on community, already has description -add column local boolean not null default true, -add column private_key text, -- These need to be generated from code -add column public_key text, -add column last_refreshed_at timestamp not null default now() -- Used to re-fetch federated actor periodically + ADD COLUMN actor_id character varying(255) NOT NULL DEFAULT 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local + ADD COLUMN bio text, -- not on community, already has description + ADD COLUMN local boolean NOT NULL DEFAULT TRUE, + ADD COLUMN private_key text, -- These need to be generated from code + ADD COLUMN public_key text, + ADD COLUMN last_refreshed_at timestamp NOT NULL DEFAULT now() -- Used to re-fetch federated actor periodically ; -- Community -alter table community -add column actor_id character varying(255) not null default 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local -add column local boolean not null default true, -add column private_key text, -- These need to be generated from code -add column public_key text, -add column last_refreshed_at timestamp not null default now() -- Used to re-fetch federated actor periodically +ALTER TABLE community + ADD COLUMN actor_id character varying(255) NOT NULL DEFAULT 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local + ADD COLUMN local boolean NOT NULL DEFAULT TRUE, + ADD COLUMN private_key text, -- These need to be generated from code + ADD COLUMN public_key text, + ADD COLUMN last_refreshed_at timestamp NOT NULL DEFAULT now() -- Used to re-fetch federated actor periodically ; -- Don't worry about rebuilding the views right now. - diff --git a/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql b/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql index 50c95bb2a..6df4cb9d9 100644 --- a/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql +++ b/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql @@ -1,7 +1,8 @@ -alter table post -drop column ap_id, -drop column local; +ALTER TABLE post + DROP COLUMN ap_id, + DROP COLUMN local; + +ALTER TABLE comment + DROP COLUMN ap_id, + DROP COLUMN local; -alter table comment -drop column ap_id, -drop column local; diff --git a/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql b/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql index 6c930cd8d..ab72ac21d 100644 --- a/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql +++ b/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql @@ -1,14 +1,11 @@ -- Add federation columns to post, comment - -alter table post +ALTER TABLE post -- TODO uniqueness constraints should be added on these 3 columns later -add column ap_id character varying(255) not null default 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local -add column local boolean not null default true -; + ADD COLUMN ap_id character varying(255) NOT NULL DEFAULT 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local + ADD COLUMN local boolean NOT NULL DEFAULT TRUE; -alter table comment +ALTER TABLE comment -- TODO uniqueness constraints should be added on these 3 columns later -add column ap_id character varying(255) not null default 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local -add column local boolean not null default true -; + ADD COLUMN ap_id character varying(255) NOT NULL DEFAULT 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local + ADD COLUMN local boolean NOT NULL DEFAULT TRUE; diff --git a/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql b/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql index 46fc953a9..d2be7d337 100644 --- a/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql +++ b/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql @@ -1,36 +1,69 @@ -- User table -drop view user_view cascade; +DROP VIEW user_view CASCADE; -alter table user_ -add column fedi_name varchar(40) not null default 'http://fake.com'; +ALTER TABLE user_ + ADD COLUMN fedi_name varchar(40) NOT NULL DEFAULT 'http://fake.com'; -alter table user_ -add constraint user__name_fedi_name_key unique (name, fedi_name); +ALTER TABLE user_ + ADD CONSTRAINT user__name_fedi_name_key UNIQUE (name, fedi_name); -- Community -alter table community -add constraint community_name_key unique (name); +ALTER TABLE community + ADD CONSTRAINT community_name_key UNIQUE (name); +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.fedi_name, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.fedi_name, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; -create materialized view user_mview as select * from user_view; +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -create unique index idx_user_mview_id on user_mview (id); diff --git a/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql b/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql index de65191d8..1d3ba63fc 100644 --- a/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql +++ b/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql @@ -1,38 +1,70 @@ -- User table - -- Need to regenerate user_view, user_mview -drop view user_view cascade; +DROP VIEW user_view CASCADE; -- Remove the fedi_name constraint, drop that useless column -alter table user_ -drop constraint user__name_fedi_name_key; +ALTER TABLE user_ + DROP CONSTRAINT user__name_fedi_name_key; -alter table user_ -drop column fedi_name; +ALTER TABLE user_ + DROP COLUMN fedi_name; -- Community -alter table community -drop constraint community_name_key; +ALTER TABLE community + DROP CONSTRAINT community_name_key; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create materialized view user_mview as select * from user_view; +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; -create unique index idx_user_mview_id on user_mview (id); +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); diff --git a/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql b/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql index ce2dde39e..2e88d51fe 100644 --- a/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql +++ b/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql @@ -1,345 +1,715 @@ -- user_view -drop view user_view cascade; +DROP VIEW user_view CASCADE; -create view user_view as -select -u.id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + u.id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create materialized view user_mview as select * from user_view; +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; -create unique index idx_user_mview_id on user_mview (id); +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- community_view -drop view community_aggregates_view cascade; -create view community_aggregates_view as -select c.*, -(select name from user_ u where c.creator_id = u.id) as creator_name, -(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, -(select name from category ct where c.category_id = ct.id) as category_name, -(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, -(select count(*) from post p where p.community_id = c.id) as number_of_posts, -(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, -hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank -from community c; +DROP VIEW community_aggregates_view CASCADE; -create materialized view community_aggregates_mview as select * from community_aggregates_view; +CREATE VIEW community_aggregates_view AS +SELECT + c.*, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c; -create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); +CREATE MATERIALIZED VIEW community_aggregates_mview AS +SELECT + * +FROM + community_aggregates_view; -create view community_view as -with all_community as -( - select - ca.* - from community_aggregates_view ca +CREATE UNIQUE INDEX idx_community_aggregates_mview_id ON community_aggregates_mview (id); + +CREATE VIEW community_view AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_view ca ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -create view community_mview as -with all_community as -( - select - ca.* - from community_aggregates_mview ca +CREATE VIEW community_mview AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- community views -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; +DROP VIEW community_moderator_view; -create view community_moderator_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select name from community c where cm.community_id = c.id) as community_name -from community_moderator cm; +DROP VIEW community_follower_view; -create view community_follower_view as -select *, -(select name from user_ u where cf.user_id = u.id) as user_name, -(select avatar from user_ u where cf.user_id = u.id), -(select name from community c where cf.community_id = c.id) as community_name -from community_follower cf; +DROP VIEW community_user_ban_view; -create view community_user_ban_view as -select *, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select name from community c where cm.community_id = c.id) as community_name -from community_user_ban cm; +CREATE VIEW community_moderator_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_moderator cm; + +CREATE VIEW community_follower_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cf.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cf.community_id = c.id) AS community_name +FROM + community_follower cf; + +CREATE VIEW community_user_ban_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_user_ban cm; -- post_view -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- reply_view, comment_view, user_mention -drop view reply_view; -drop view user_mention_view; -drop view user_mention_mview; -drop view comment_view; -drop view comment_mview; -drop materialized view comment_aggregates_mview; -drop view comment_aggregates_view; +DROP VIEW reply_view; + +DROP VIEW user_mention_view; + +DROP VIEW user_mention_mview; + +DROP VIEW comment_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP VIEW comment_aggregates_view; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + co.name + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_name, + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(cl.score), 0), c.published) AS hot_rank +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.post_id, c.parent_id, @@ -363,21 +733,22 @@ select c.my_vote, c.saved, um.recipient_id -from user_mention um, comment_view c -where um.comment_id = c.id; +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; - -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -397,20 +768,27 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.post_id, ac.parent_id, @@ -430,11 +808,11 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql b/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql index 02499fc24..534ecdc29 100644 --- a/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql +++ b/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql @@ -1,384 +1,890 @@ -- user_view -drop view user_view cascade; +DROP VIEW user_view CASCADE; -create view user_view as -select -u.id, -u.actor_id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.bio, -u.local, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE VIEW user_view AS +SELECT + u.id, + u.actor_id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.bio, + u.local, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; -create materialized view user_mview as select * from user_view; +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; -create unique index idx_user_mview_id on user_mview (id); +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- community_view -drop view community_aggregates_view cascade; -create view community_aggregates_view as +DROP VIEW community_aggregates_view CASCADE; + +CREATE VIEW community_aggregates_view AS -- Now that there's public and private keys, you have to be explicit here -select c.id, -c.name, -c.title, -c.description, -c.category_id, -c.creator_id, -c.removed, -c.published, -c.updated, -c.deleted, -c.nsfw, -c.actor_id, -c.local, -c.last_refreshed_at, -(select actor_id from user_ u where c.creator_id = u.id) as creator_actor_id, -(select local from user_ u where c.creator_id = u.id) as creator_local, -(select name from user_ u where c.creator_id = u.id) as creator_name, -(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, -(select name from category ct where c.category_id = ct.id) as category_name, -(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, -(select count(*) from post p where p.community_id = c.id) as number_of_posts, -(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, -hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank -from community c; +SELECT + c.id, + c.name, + c.title, + c.description, + c.category_id, + c.creator_id, + c.removed, + c.published, + c.updated, + c.deleted, + c.nsfw, + c.actor_id, + c.local, + c.last_refreshed_at, + ( + SELECT + actor_id + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_local, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c; -create materialized view community_aggregates_mview as select * from community_aggregates_view; +CREATE MATERIALIZED VIEW community_aggregates_mview AS +SELECT + * +FROM + community_aggregates_view; -create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); +CREATE UNIQUE INDEX idx_community_aggregates_mview_id ON community_aggregates_mview (id); -create view community_view as -with all_community as -( - select - ca.* - from community_aggregates_view ca +CREATE VIEW community_view AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_view ca ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -create view community_mview as -with all_community as -( - select - ca.* - from community_aggregates_mview ca +CREATE VIEW community_mview AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -- community views -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; +DROP VIEW community_moderator_view; -create view community_moderator_view as -select *, -(select actor_id from user_ u where cm.user_id = u.id) as user_actor_id, -(select local from user_ u where cm.user_id = u.id) as user_local, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select actor_id from community c where cm.community_id = c.id) as community_actor_id, -(select local from community c where cm.community_id = c.id) as community_local, -(select name from community c where cm.community_id = c.id) as community_name -from community_moderator cm; +DROP VIEW community_follower_view; -create view community_follower_view as -select *, -(select actor_id from user_ u where cf.user_id = u.id) as user_actor_id, -(select local from user_ u where cf.user_id = u.id) as user_local, -(select name from user_ u where cf.user_id = u.id) as user_name, -(select avatar from user_ u where cf.user_id = u.id), -(select actor_id from community c where cf.community_id = c.id) as community_actor_id, -(select local from community c where cf.community_id = c.id) as community_local, -(select name from community c where cf.community_id = c.id) as community_name -from community_follower cf; +DROP VIEW community_user_ban_view; -create view community_user_ban_view as -select *, -(select actor_id from user_ u where cm.user_id = u.id) as user_actor_id, -(select local from user_ u where cm.user_id = u.id) as user_local, -(select name from user_ u where cm.user_id = u.id) as user_name, -(select avatar from user_ u where cm.user_id = u.id), -(select actor_id from community c where cm.community_id = c.id) as community_actor_id, -(select local from community c where cm.community_id = c.id) as community_local, -(select name from community c where cm.community_id = c.id) as community_name -from community_user_ban cm; +CREATE VIEW community_moderator_view AS +SELECT + *, + ( + SELECT + actor_id + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_local, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + actor_id + FROM + community c + WHERE + cm.community_id = c.id) AS community_actor_id, + ( + SELECT + local + FROM + community c + WHERE + cm.community_id = c.id) AS community_local, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_moderator cm; + +CREATE VIEW community_follower_view AS +SELECT + *, + ( + SELECT + actor_id + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_local, + ( + SELECT + name + FROM + user_ u + WHERE + cf.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cf.user_id = u.id), ( + SELECT + actor_id + FROM + community c + WHERE + cf.community_id = c.id) AS community_actor_id, + ( + SELECT + local + FROM + community c + WHERE + cf.community_id = c.id) AS community_local, + ( + SELECT + name + FROM + community c + WHERE + cf.community_id = c.id) AS community_name +FROM + community_follower cf; + +CREATE VIEW community_user_ban_view AS +SELECT + *, + ( + SELECT + actor_id + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_local, + ( + SELECT + name + FROM + user_ u + WHERE + cm.user_id = u.id) AS user_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + cm.user_id = u.id), ( + SELECT + actor_id + FROM + community c + WHERE + cm.community_id = c.id) AS community_actor_id, + ( + SELECT + local + FROM + community c + WHERE + cm.community_id = c.id) AS community_local, + ( + SELECT + name + FROM + community c + WHERE + cm.community_id = c.id) AS community_name +FROM + community_user_ban cm; -- post_view -drop view post_view; -drop view post_mview; -drop materialized view post_aggregates_mview; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select actor_id from user_ where p.creator_id = user_.id) as creator_actor_id, -(select local from user_ where p.creator_id = user_.id) as creator_local, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select actor_id from community where p.community_id = community.id) as community_actor_id, -(select local from community where p.community_id = community.id) as community_local, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + actor_id + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_local, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + actor_id + FROM + community + WHERE + p.community_id = community.id) AS community_actor_id, + ( + SELECT + local + FROM + community + WHERE + p.community_id = community.id) AS community_local, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id - -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -- reply_view, comment_view, user_mention -drop view reply_view; -drop view user_mention_view; -drop view user_mention_mview; -drop view comment_view; -drop view comment_mview; -drop materialized view comment_aggregates_mview; -drop view comment_aggregates_view; +DROP VIEW reply_view; + +DROP VIEW user_mention_view; + +DROP VIEW user_mention_mview; + +DROP VIEW comment_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP VIEW comment_aggregates_view; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select co.actor_id from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_actor_id, -(select co.local from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_local, -(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select actor_id from user_ where c.creator_id = user_.id) as creator_actor_id, -(select local from user_ where c.creator_id = user_.id) as creator_local, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + co.actor_id + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_actor_id, + ( + SELECT + co.local + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_local, + ( + SELECT + co.name + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_name, + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + actor_id + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_local, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(cl.score), 0), c.published) AS hot_rank +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -406,23 +912,36 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; - -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -446,22 +965,41 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -485,13 +1023,25 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-04-21-123957_remove_unique_user_constraints/down.sql b/migrations/2020-04-21-123957_remove_unique_user_constraints/down.sql index a172581a1..c81289418 100644 --- a/migrations/2020-04-21-123957_remove_unique_user_constraints/down.sql +++ b/migrations/2020-04-21-123957_remove_unique_user_constraints/down.sql @@ -1,4 +1,5 @@ -- The username index -drop index idx_user_name_lower_actor_id; -create unique index idx_user_name_lower on user_ (lower(name)); +DROP INDEX idx_user_name_lower_actor_id; + +CREATE UNIQUE INDEX idx_user_name_lower ON user_ (lower(name)); diff --git a/migrations/2020-04-21-123957_remove_unique_user_constraints/up.sql b/migrations/2020-04-21-123957_remove_unique_user_constraints/up.sql index 969eab0b6..5843fa281 100644 --- a/migrations/2020-04-21-123957_remove_unique_user_constraints/up.sql +++ b/migrations/2020-04-21-123957_remove_unique_user_constraints/up.sql @@ -1,2 +1,4 @@ -drop index idx_user_name_lower; -create unique index idx_user_name_lower_actor_id on user_ (lower(name), lower(actor_id)); +DROP INDEX idx_user_name_lower; + +CREATE UNIQUE INDEX idx_user_name_lower_actor_id ON user_ (lower(name), lower(actor_id)); + diff --git a/migrations/2020-05-05-210233_add_activitypub_for_private_messages/down.sql b/migrations/2020-05-05-210233_add_activitypub_for_private_messages/down.sql index 15c928592..76c74f6ea 100644 --- a/migrations/2020-05-05-210233_add_activitypub_for_private_messages/down.sql +++ b/migrations/2020-05-05-210233_add_activitypub_for_private_messages/down.sql @@ -1,21 +1,28 @@ -drop materialized view private_message_mview; -drop view private_message_view; +DROP MATERIALIZED VIEW private_message_mview; -alter table private_message -drop column ap_id, -drop column local; +DROP VIEW private_message_view; -create view private_message_view as -select -pm.*, -u.name as creator_name, -u.avatar as creator_avatar, -u2.name as recipient_name, -u2.avatar as recipient_avatar -from private_message pm -inner join user_ u on u.id = pm.creator_id -inner join user_ u2 on u2.id = pm.recipient_id; +ALTER TABLE private_message + DROP COLUMN ap_id, + DROP COLUMN local; -create materialized view private_message_mview as select * from private_message_view; +CREATE VIEW private_message_view AS +SELECT + pm.*, + u.name AS creator_name, + u.avatar AS creator_avatar, + u2.name AS recipient_name, + u2.avatar AS recipient_avatar +FROM + private_message pm + INNER JOIN user_ u ON u.id = pm.creator_id + INNER JOIN user_ u2 ON u2.id = pm.recipient_id; + +CREATE MATERIALIZED VIEW private_message_mview AS +SELECT + * +FROM + private_message_view; + +CREATE UNIQUE INDEX idx_private_message_mview_id ON private_message_mview (id); -create unique index idx_private_message_mview_id on private_message_mview (id); diff --git a/migrations/2020-05-05-210233_add_activitypub_for_private_messages/up.sql b/migrations/2020-05-05-210233_add_activitypub_for_private_messages/up.sql index 9f152ada6..6935d33cb 100644 --- a/migrations/2020-05-05-210233_add_activitypub_for_private_messages/up.sql +++ b/migrations/2020-05-05-210233_add_activitypub_for_private_messages/up.sql @@ -1,25 +1,32 @@ -alter table private_message -add column ap_id character varying(255) not null default 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local -add column local boolean not null default true -; +ALTER TABLE private_message + ADD COLUMN ap_id character varying(255) NOT NULL DEFAULT 'http://fake.com', -- This needs to be checked and updated in code, building from the site url if local + ADD COLUMN local boolean NOT NULL DEFAULT TRUE; -drop materialized view private_message_mview; -drop view private_message_view; -create view private_message_view as -select -pm.*, -u.name as creator_name, -u.avatar as creator_avatar, -u.actor_id as creator_actor_id, -u.local as creator_local, -u2.name as recipient_name, -u2.avatar as recipient_avatar, -u2.actor_id as recipient_actor_id, -u2.local as recipient_local -from private_message pm -inner join user_ u on u.id = pm.creator_id -inner join user_ u2 on u2.id = pm.recipient_id; +DROP MATERIALIZED VIEW private_message_mview; -create materialized view private_message_mview as select * from private_message_view; +DROP VIEW private_message_view; + +CREATE VIEW private_message_view AS +SELECT + pm.*, + u.name AS creator_name, + u.avatar AS creator_avatar, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u2.name AS recipient_name, + u2.avatar AS recipient_avatar, + u2.actor_id AS recipient_actor_id, + u2.local AS recipient_local +FROM + private_message pm + INNER JOIN user_ u ON u.id = pm.creator_id + INNER JOIN user_ u2 ON u2.id = pm.recipient_id; + +CREATE MATERIALIZED VIEW private_message_mview AS +SELECT + * +FROM + private_message_view; + +CREATE UNIQUE INDEX idx_private_message_mview_id ON private_message_mview (id); -create unique index idx_private_message_mview_id on private_message_mview (id); diff --git a/migrations/2020-06-30-135809_remove_mat_views/down.sql b/migrations/2020-06-30-135809_remove_mat_views/down.sql index 5f72b76d1..ea82e57b4 100644 --- a/migrations/2020-06-30-135809_remove_mat_views/down.sql +++ b/migrations/2020-06-30-135809_remove_mat_views/down.sql @@ -1,422 +1,811 @@ -- Dropping all the fast tables -drop table user_fast; -drop view post_fast_view; -drop table post_aggregates_fast; -drop view community_fast_view; -drop table community_aggregates_fast; -drop view reply_fast_view; -drop view user_mention_fast_view; -drop view comment_fast_view; -drop table comment_aggregates_fast; +DROP TABLE user_fast; + +DROP VIEW post_fast_view; + +DROP TABLE post_aggregates_fast; + +DROP VIEW community_fast_view; + +DROP TABLE community_aggregates_fast; + +DROP VIEW reply_fast_view; + +DROP VIEW user_mention_fast_view; + +DROP VIEW comment_fast_view; + +DROP TABLE comment_aggregates_fast; -- Re-adding all the triggers, functions, and mviews - -- private message -create materialized view private_message_mview as select * from private_message_view; - -create unique index idx_private_message_mview_id on private_message_mview (id); +CREATE MATERIALIZED VIEW private_message_mview AS +SELECT + * +FROM + private_message_view; +CREATE UNIQUE INDEX idx_private_message_mview_id ON private_message_mview (id); -- Create the triggers -create or replace function refresh_private_message() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently private_message_mview; - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_private_message () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY private_message_mview; + RETURN NULL; +END +$$; -create trigger refresh_private_message -after insert or update or delete or truncate -on private_message -for each statement -execute procedure refresh_private_message(); +CREATE TRIGGER refresh_private_message + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON private_message + FOR EACH statement + EXECUTE PROCEDURE refresh_private_message (); --- user -create or replace function refresh_user() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently user_mview; - refresh materialized view concurrently comment_aggregates_mview; -- cause of bans - refresh materialized view concurrently post_aggregates_mview; - return null; -end $$; +-- user +CREATE OR REPLACE FUNCTION refresh_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY comment_aggregates_mview; + -- cause of bans + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + RETURN NULL; +END +$$; -drop trigger refresh_user on user_; -create trigger refresh_user -after insert or update or delete or truncate -on user_ -for each statement -execute procedure refresh_user(); -drop view user_view cascade; +DROP TRIGGER refresh_user ON user_; -create view user_view as -select -u.id, -u.actor_id, -u.name, -u.avatar, -u.email, -u.matrix_user_id, -u.bio, -u.local, -u.admin, -u.banned, -u.show_avatars, -u.send_notifications_to_email, -u.published, -(select count(*) from post p where p.creator_id = u.id) as number_of_posts, -(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, -(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, -(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score -from user_ u; +CREATE TRIGGER refresh_user + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON user_ + FOR EACH statement + EXECUTE PROCEDURE refresh_user (); -create materialized view user_mview as select * from user_view; +DROP VIEW user_view CASCADE; -create unique index idx_user_mview_id on user_mview (id); +CREATE VIEW user_view AS +SELECT + u.id, + u.actor_id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.bio, + u.local, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + ( + SELECT + count(*) + FROM + post p + WHERE + p.creator_id = u.id) AS number_of_posts, + ( + SELECT + coalesce(sum(score), 0) + FROM + post p, + post_like pl + WHERE + u.id = p.creator_id + AND p.id = pl.post_id) AS post_score, + ( + SELECT + count(*) + FROM + comment c + WHERE + c.creator_id = u.id) AS number_of_comments, + ( + SELECT + coalesce(sum(score), 0) + FROM + comment c, + comment_like cl + WHERE + u.id = c.creator_id + AND c.id = cl.comment_id) AS comment_score +FROM + user_ u; + +CREATE MATERIALIZED VIEW user_mview AS +SELECT + * +FROM + user_view; + +CREATE UNIQUE INDEX idx_user_mview_id ON user_mview (id); -- community -drop trigger refresh_community on community; -create trigger refresh_community -after insert or update or delete or truncate -on community -for each statement -execute procedure refresh_community(); +DROP TRIGGER refresh_community ON community; -create or replace function refresh_community() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently community_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE TRIGGER refresh_community + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON community + FOR EACH statement + EXECUTE PROCEDURE refresh_community (); -drop view community_aggregates_view cascade; -create view community_aggregates_view as +CREATE OR REPLACE FUNCTION refresh_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY community_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; + +DROP VIEW community_aggregates_view CASCADE; + +CREATE VIEW community_aggregates_view AS -- Now that there's public and private keys, you have to be explicit here -select c.id, -c.name, -c.title, -c.description, -c.category_id, -c.creator_id, -c.removed, -c.published, -c.updated, -c.deleted, -c.nsfw, -c.actor_id, -c.local, -c.last_refreshed_at, -(select actor_id from user_ u where c.creator_id = u.id) as creator_actor_id, -(select local from user_ u where c.creator_id = u.id) as creator_local, -(select name from user_ u where c.creator_id = u.id) as creator_name, -(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, -(select name from category ct where c.category_id = ct.id) as category_name, -(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, -(select count(*) from post p where p.community_id = c.id) as number_of_posts, -(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, -hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank -from community c; +SELECT + c.id, + c.name, + c.title, + c.description, + c.category_id, + c.creator_id, + c.removed, + c.published, + c.updated, + c.deleted, + c.nsfw, + c.actor_id, + c.local, + c.last_refreshed_at, + ( + SELECT + actor_id + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_local, + ( + SELECT + name + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + c.creator_id = u.id) AS creator_avatar, + ( + SELECT + name + FROM + category ct + WHERE + c.category_id = ct.id) AS category_name, + ( + SELECT + count(*) + FROM + community_follower cf + WHERE + cf.community_id = c.id) AS number_of_subscribers, + ( + SELECT + count(*) + FROM + post p + WHERE + p.community_id = c.id) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment co, + post p + WHERE + c.id = p.community_id + AND p.id = co.post_id) AS number_of_comments, + hot_rank (( + SELECT + count(*) + FROM community_follower cf + WHERE + cf.community_id = c.id), c.published) AS hot_rank +FROM + community c; -create materialized view community_aggregates_mview as select * from community_aggregates_view; +CREATE MATERIALIZED VIEW community_aggregates_mview AS +SELECT + * +FROM + community_aggregates_view; -create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); +CREATE UNIQUE INDEX idx_community_aggregates_mview_id ON community_aggregates_mview (id); -create view community_view as -with all_community as -( - select - ca.* - from community_aggregates_view ca +CREATE VIEW community_view AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_view ca ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; - -create view community_mview as -with all_community as -( - select - ca.* - from community_aggregates_mview ca +CREATE VIEW community_mview AS +with all_community AS ( + SELECT + ca.* + FROM + community_aggregates_mview ca ) +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN all_community ac +UNION ALL +SELECT + ac.*, + NULL AS user_id, + NULL AS subscribed +FROM + all_community ac; -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join all_community ac - -union all - -select -ac.*, -null as user_id, -null as subscribed -from all_community ac -; -- Post -drop view post_view; -drop view post_aggregates_view; +DROP VIEW post_view; + +DROP VIEW post_aggregates_view; -- regen post view -create view post_aggregates_view as -select -p.*, -(select u.banned from user_ u where p.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, -(select actor_id from user_ where p.creator_id = user_.id) as creator_actor_id, -(select local from user_ where p.creator_id = user_.id) as creator_local, -(select name from user_ where p.creator_id = user_.id) as creator_name, -(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, -(select actor_id from community where p.community_id = community.id) as community_actor_id, -(select local from community where p.community_id = community.id) as community_local, -(select name from community where p.community_id = community.id) as community_name, -(select removed from community c where p.community_id = c.id) as community_removed, -(select deleted from community c where p.community_id = c.id) as community_deleted, -(select nsfw from community c where p.community_id = c.id) as community_nsfw, -(select count(*) from comment where comment.post_id = p.id) as number_of_comments, -coalesce(sum(pl.score), 0) as score, -count (case when pl.score = 1 then 1 else null end) as upvotes, -count (case when pl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(pl.score) , 0), - ( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end - ) -) as hot_rank, -( - case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps - else greatest(c.recent_comment_time, p.published) - end -) as newest_activity_time -from post p -left join post_like pl on p.id = pl.post_id -left join ( - select post_id, - max(published) as recent_comment_time - from comment - group by 1 -) c on p.id = c.post_id -group by p.id, c.recent_comment_time; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + ( + SELECT + u.banned + FROM + user_ u + WHERE + p.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb + WHERE + p.creator_id = cb.user_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + actor_id + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_local, + ( + SELECT + name + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + p.creator_id = user_.id) AS creator_avatar, + ( + SELECT + actor_id + FROM + community + WHERE + p.community_id = community.id) AS community_actor_id, + ( + SELECT + local + FROM + community + WHERE + p.community_id = community.id) AS community_local, + ( + SELECT + name + FROM + community + WHERE + p.community_id = community.id) AS community_name, + ( + SELECT + removed + FROM + community c + WHERE + p.community_id = c.id) AS community_removed, + ( + SELECT + deleted + FROM + community c + WHERE + p.community_id = c.id) AS community_deleted, + ( + SELECT + nsfw + FROM + community c + WHERE + p.community_id = c.id) AS community_nsfw, + ( + SELECT + count(*) + FROM + comment + WHERE + comment.post_id = p.id) AS number_of_comments, + coalesce(sum(pl.score), 0) AS score, + count( + CASE WHEN pl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN pl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(pl.score), 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published -- Prevents necro-bumps + ELSE + greatest (c.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + LEFT JOIN ( + SELECT + post_id, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + 1) c ON p.id = c.post_id +GROUP BY + p.id, + c.recent_comment_time; -create materialized view post_aggregates_mview as select * from post_aggregates_view; +CREATE MATERIALIZED VIEW post_aggregates_mview AS +SELECT + * +FROM + post_aggregates_view; -create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); +CREATE UNIQUE INDEX idx_post_aggregates_mview_id ON post_aggregates_mview (id); -create view post_view as -with all_post as ( - select - pa.* - from post_aggregates_view pa +CREATE VIEW post_view AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_view pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all - -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -create view post_mview as -with all_post as ( - select - pa.* - from post_aggregates_mview pa +CREATE VIEW post_mview AS +with all_post AS ( + SELECT + pa.* + FROM + post_aggregates_mview pa ) -select -ap.*, -u.id as user_id, -coalesce(pl.score, 0) as my_vote, -(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, -(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, -(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved -from user_ u -cross join all_post ap -left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id +SELECT + ap.*, + u.id AS user_id, + coalesce(pl.score, 0) AS my_vote, + ( + SELECT + cf.id::bool + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND cf.community_id = ap.community_id) AS subscribed, + ( + SELECT + pr.id::bool + FROM + post_read pr + WHERE + u.id = pr.user_id + AND pr.post_id = ap.id) AS read, + ( + SELECT + ps.id::bool + FROM + post_saved ps + WHERE + u.id = ps.user_id + AND ps.post_id = ap.id) AS saved +FROM + user_ u + CROSS JOIN all_post ap + LEFT JOIN post_like pl ON u.id = pl.user_id + AND ap.id = pl.post_id + UNION ALL + SELECT + ap.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved + FROM + all_post ap; -union all +DROP TRIGGER refresh_post ON post; -select -ap.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from all_post ap -; - -drop trigger refresh_post on post; -create trigger refresh_post -after insert or update or delete or truncate -on post -for each statement -execute procedure refresh_post(); - -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - refresh materialized view concurrently post_aggregates_mview; - refresh materialized view concurrently user_mview; - return null; -end $$; +CREATE TRIGGER refresh_post + AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON post + FOR EACH statement + EXECUTE PROCEDURE refresh_post (); +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + REFRESH MATERIALIZED VIEW CONCURRENTLY post_aggregates_mview; + REFRESH MATERIALIZED VIEW CONCURRENTLY user_mview; + RETURN NULL; +END +$$; -- User mention, comment, reply -drop view user_mention_view; -drop view comment_view; -drop view comment_aggregates_view; +DROP VIEW user_mention_view; + +DROP VIEW comment_view; + +DROP VIEW comment_aggregates_view; -- reply and comment view -create view comment_aggregates_view as -select -c.*, -(select community_id from post p where p.id = c.post_id), -(select co.actor_id from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_actor_id, -(select co.local from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_local, -(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, -(select u.banned from user_ u where c.creator_id = u.id) as banned, -(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, -(select actor_id from user_ where c.creator_id = user_.id) as creator_actor_id, -(select local from user_ where c.creator_id = user_.id) as creator_local, -(select name from user_ where c.creator_id = user_.id) as creator_name, -(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, -coalesce(sum(cl.score), 0) as score, -count (case when cl.score = 1 then 1 else null end) as upvotes, -count (case when cl.score = -1 then 1 else null end) as downvotes, -hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank -from comment c -left join comment_like cl on c.id = cl.comment_id -group by c.id; +CREATE VIEW comment_aggregates_view AS +SELECT + c.*, + ( + SELECT + community_id + FROM + post p + WHERE + p.id = c.post_id), ( + SELECT + co.actor_id + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_actor_id, + ( + SELECT + co.local + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_local, + ( + SELECT + co.name + FROM + post p, + community co + WHERE + p.id = c.post_id + AND p.community_id = co.id) AS community_name, + ( + SELECT + u.banned + FROM + user_ u + WHERE + c.creator_id = u.id) AS banned, + ( + SELECT + cb.id::bool + FROM + community_user_ban cb, + post p + WHERE + c.creator_id = cb.user_id + AND p.id = c.post_id + AND p.community_id = cb.community_id) AS banned_from_community, + ( + SELECT + actor_id + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_actor_id, + ( + SELECT + local + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_local, + ( + SELECT + name + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ + WHERE + c.creator_id = user_.id) AS creator_avatar, + coalesce(sum(cl.score), 0) AS score, + count( + CASE WHEN cl.score = 1 THEN + 1 + ELSE + NULL + END) AS upvotes, + count( + CASE WHEN cl.score = - 1 THEN + 1 + ELSE + NULL + END) AS downvotes, + hot_rank (coalesce(sum(cl.score), 0), c.published) AS hot_rank +FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + c.id; -create materialized view comment_aggregates_mview as select * from comment_aggregates_view; +CREATE MATERIALIZED VIEW comment_aggregates_mview AS +SELECT + * +FROM + comment_aggregates_view; -create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); +CREATE UNIQUE INDEX idx_comment_aggregates_mview_id ON comment_aggregates_mview (id); -create view comment_view as -with all_comment as -( - select - ca.* - from comment_aggregates_view ca +CREATE VIEW comment_view AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_view ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -create view comment_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW comment_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select -ac.*, -u.id as user_id, -coalesce(cl.score, 0) as my_vote, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, -(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id - -union all - -select +SELECT ac.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from all_comment ac -; + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.community_id = cf.community_id) AS subscribed, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + UNION ALL + SELECT + ac.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved + FROM + all_comment ac; -- Do the reply_view referencing the comment_mview -create view reply_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_mview cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_mview cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -444,23 +833,36 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; - -create view user_mention_mview as -with all_comment as -( - select - ca.* - from comment_aggregates_mview ca +CREATE VIEW user_mention_mview AS +with all_comment AS ( + SELECT + ca.* + FROM + comment_aggregates_mview ca ) - -select +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -484,22 +886,41 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join all_comment ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN all_comment ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -523,13 +944,25 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from all_comment ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + all_comment ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; diff --git a/migrations/2020-06-30-135809_remove_mat_views/up.sql b/migrations/2020-06-30-135809_remove_mat_views/up.sql index bd792a8b9..0c633597e 100644 --- a/migrations/2020-06-30-135809_remove_mat_views/up.sql +++ b/migrations/2020-06-30-135809_remove_mat_views/up.sql @@ -1,301 +1,399 @@ -- Drop the mviews -drop view post_mview; -drop materialized view user_mview; -drop view community_mview; -drop materialized view private_message_mview; -drop view user_mention_mview; -drop view reply_view; -drop view comment_mview; -drop materialized view post_aggregates_mview; -drop materialized view community_aggregates_mview; -drop materialized view comment_aggregates_mview; -drop trigger refresh_private_message on private_message; +DROP VIEW post_mview; + +DROP MATERIALIZED VIEW user_mview; + +DROP VIEW community_mview; + +DROP MATERIALIZED VIEW private_message_mview; + +DROP VIEW user_mention_mview; + +DROP VIEW reply_view; + +DROP VIEW comment_mview; + +DROP MATERIALIZED VIEW post_aggregates_mview; + +DROP MATERIALIZED VIEW community_aggregates_mview; + +DROP MATERIALIZED VIEW comment_aggregates_mview; + +DROP TRIGGER refresh_private_message ON private_message; -- User -drop view user_view; -create view user_view as -select - u.id, - u.actor_id, - u.name, - u.avatar, - u.email, - u.matrix_user_id, - u.bio, - u.local, - u.admin, - u.banned, - u.show_avatars, - u.send_notifications_to_email, - u.published, - coalesce(pd.posts, 0) as number_of_posts, - coalesce(pd.score, 0) as post_score, - coalesce(cd.comments, 0) as number_of_comments, - coalesce(cd.score, 0) as comment_score -from user_ u -left join ( - select - p.creator_id as creator_id, - count(distinct p.id) as posts, - sum(pl.score) as score - from post p - join post_like pl on p.id = pl.post_id - group by p.creator_id -) pd on u.id = pd.creator_id -left join ( - select - c.creator_id, - count(distinct c.id) as comments, - sum(cl.score) as score - from comment c - join comment_like cl on c.id = cl.comment_id - group by c.creator_id -) cd on u.id = cd.creator_id; +DROP VIEW user_view; +CREATE VIEW user_view AS +SELECT + u.id, + u.actor_id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.bio, + u.local, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + coalesce(pd.posts, 0) AS number_of_posts, + coalesce(pd.score, 0) AS post_score, + coalesce(cd.comments, 0) AS number_of_comments, + coalesce(cd.score, 0) AS comment_score +FROM + user_ u + LEFT JOIN ( + SELECT + p.creator_id AS creator_id, + count(DISTINCT p.id) AS posts, + sum(pl.score) AS score + FROM + post p + JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.creator_id) pd ON u.id = pd.creator_id + LEFT JOIN ( + SELECT + c.creator_id, + count(DISTINCT c.id) AS comments, + sum(cl.score) AS score + FROM + comment c + JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.creator_id) cd ON u.id = cd.creator_id; -create table user_fast as select * from user_view; -alter table user_fast add primary key (id); +CREATE TABLE user_fast AS +SELECT + * +FROM + user_view; -drop trigger refresh_user on user_; +ALTER TABLE user_fast + ADD PRIMARY KEY (id); -create trigger refresh_user -after insert or update or delete -on user_ -for each row -execute procedure refresh_user(); +DROP TRIGGER refresh_user ON user_; --- Sample insert +CREATE TRIGGER refresh_user + AFTER INSERT OR UPDATE OR DELETE ON user_ + FOR EACH ROW + EXECUTE PROCEDURE refresh_user (); + +-- Sample insert -- insert into user_(name, password_encrypted) values ('test_name', 'bleh'); -- Sample delete -- delete from user_ where name like 'test_name'; -- Sample update -- update user_ set avatar = 'hai' where name like 'test_name'; -create or replace function refresh_user() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from user_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from user_fast where id = OLD.id; - insert into user_fast select * from user_view where id = NEW.id; - - -- Refresh post_fast, cause of user info changes - delete from post_aggregates_fast where creator_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where creator_id = NEW.id; - - delete from comment_aggregates_fast where creator_id = NEW.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where creator_id = NEW.id; - - ELSIF (TG_OP = 'INSERT') THEN - insert into user_fast select * from user_view where id = NEW.id; - END IF; - - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id; + -- Refresh post_fast, cause of user info changes + DELETE FROM post_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + creator_id = NEW.id; + DELETE FROM comment_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + creator_id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; -- Post -- Redoing the views : Credit eiknat -drop view post_view; -drop view post_aggregates_view; +DROP VIEW post_view; -create view post_aggregates_view as -select - p.*, - -- creator details - u.actor_id as creator_actor_id, - u."local" as creator_local, - u."name" as creator_name, - u.avatar as creator_avatar, - u.banned as banned, - cb.id::bool as banned_from_community, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.removed as community_removed, - c.deleted as community_deleted, - c.nsfw as community_nsfw, - -- post score data/comment count - coalesce(ct.comments, 0) as number_of_comments, - coalesce(pl.score, 0) as score, - coalesce(pl.upvotes, 0) as upvotes, - coalesce(pl.downvotes, 0) as downvotes, - hot_rank( - coalesce(pl.score , 0), ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) - ) as hot_rank, - ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) as newest_activity_time -from post p -left join user_ u on p.creator_id = u.id -left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id -left join community c on p.community_id = c.id -left join ( - select - post_id, - count(*) as comments, - max(published) as recent_comment_time - from comment - group by post_id -) ct on ct.post_id = p.id -left join ( - select - post_id, - sum(score) as score, - sum(score) filter (where score = 1) as upvotes, - -sum(score) filter (where score = -1) as downvotes - from post_like - group by post_id -) pl on pl.post_id = p.id -order by p.id; +DROP VIEW post_aggregates_view; -create view post_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_view pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + -- creator details + u.actor_id AS creator_actor_id, + u."local" AS creator_local, + u."name" AS creator_name, + u.avatar AS creator_avatar, + u.banned AS banned, + cb.id::bool AS banned_from_community, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.removed AS community_removed, + c.deleted AS community_deleted, + c.nsfw AS community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) AS number_of_comments, + coalesce(pl.score, 0) AS score, + coalesce(pl.upvotes, 0) AS upvotes, + coalesce(pl.downvotes, 0) AS downvotes, + hot_rank (coalesce(pl.score, 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN user_ u ON p.creator_id = u.id + LEFT JOIN community_user_ban cb ON p.creator_id = cb.user_id + AND p.community_id = cb.community_id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN ( + SELECT + post_id, + count(*) AS comments, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_id, + sum(score) AS score, + sum(score) FILTER (WHERE score = 1) AS upvotes, + - sum(score) FILTER (WHERE score = - 1) AS downvotes + FROM + post_like + GROUP BY + post_id) pl ON pl.post_id = p.id +ORDER BY + p.id; -union all - -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_view pav; +CREATE VIEW post_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_view pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_view pav; -- The post fast table -create table post_aggregates_fast as select * from post_aggregates_view; -alter table post_aggregates_fast add primary key (id); +CREATE TABLE post_aggregates_fast AS +SELECT + * +FROM + post_aggregates_view; + +ALTER TABLE post_aggregates_fast + ADD PRIMARY KEY (id); -- For the hot rank resorting -create index idx_post_aggregates_fast_hot_rank_published on post_aggregates_fast (hot_rank desc, published desc); +CREATE INDEX idx_post_aggregates_fast_hot_rank_published ON post_aggregates_fast (hot_rank DESC, published DESC); -create view post_fast_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_fast pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE VIEW post_fast_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_fast pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_fast pav; -union all +DROP TRIGGER refresh_post ON post; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_fast pav; - -drop trigger refresh_post on post; - -create trigger refresh_post -after insert or update or delete -on post -for each row -execute procedure refresh_post(); +CREATE TRIGGER refresh_post + AFTER INSERT OR UPDATE OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE refresh_post (); -- Sample select -- select id, name from post_fast_view where name like 'test_post' and user_id is null; --- Sample insert +-- Sample insert -- insert into post(name, creator_id, community_id) values ('test_post', 2, 2); -- Sample delete -- delete from post where name like 'test_post'; -- Sample update -- update post set community_id = 4 where name like 'test_post'; -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set hot_rank = pav.hot_rank - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; -- Community -- Redoing the views : Credit eiknat -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view community_view; -drop view community_aggregates_view; +DROP VIEW community_moderator_view; -create view community_aggregates_view as -select +DROP VIEW community_follower_view; + +DROP VIEW community_user_ban_view; + +DROP VIEW community_view; + +DROP VIEW community_aggregates_view; + +CREATE VIEW community_aggregates_view AS +SELECT c.id, c.name, c.title, @@ -310,302 +408,382 @@ select c.actor_id, c.local, c.last_refreshed_at, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.avatar as creator_avatar, - cat.name as category_name, - coalesce(cf.subs, 0) as number_of_subscribers, - coalesce(cd.posts, 0) as number_of_posts, - coalesce(cd.comments, 0) as number_of_comments, - hot_rank(cf.subs, c.published) as hot_rank -from community c -left join user_ u on c.creator_id = u.id -left join category cat on c.category_id = cat.id -left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - join comment ct on p.id = ct.post_id - group by p.community_id -) cd on cd.community_id = c.id -left join ( - select - community_id, - count(*) as subs - from community_follower - group by community_id -) cf on cf.community_id = c.id; + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.avatar AS creator_avatar, + cat.name AS category_name, + coalesce(cf.subs, 0) AS number_of_subscribers, + coalesce(cd.posts, 0) AS number_of_posts, + coalesce(cd.comments, 0) AS number_of_comments, + hot_rank (cf.subs, c.published) AS hot_rank +FROM + community c + LEFT JOIN user_ u ON c.creator_id = u.id + LEFT JOIN category cat ON c.category_id = cat.id + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_id) cf ON cf.community_id = c.id; -create view community_view as -select +CREATE VIEW community_view AS +SELECT cv.*, - us.user as user_id, - us.is_subbed::bool as subscribed -from community_aggregates_view cv -cross join lateral ( - select - u.id as user, - coalesce(cf.community_id, 0) as is_subbed - from user_ u - left join community_follower cf on u.id = cf.user_id and cf.community_id = cv.id -) as us - -union all - -select + us.user AS user_id, + us.is_subbed::bool AS subscribed +FROM + community_aggregates_view cv + CROSS JOIN LATERAL ( + SELECT + u.id AS user, + coalesce(cf.community_id, 0) AS is_subbed + FROM + user_ u + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = cv.id) AS us +UNION ALL +SELECT cv.*, - null as user_id, - null as subscribed -from community_aggregates_view cv; + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_view cv; -create view community_moderator_view as -select +CREATE VIEW community_moderator_view AS +SELECT cm.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_moderator cm -left join user_ u on cm.user_id = u.id -left join community c on cm.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_moderator cm + LEFT JOIN user_ u ON cm.user_id = u.id + LEFT JOIN community c ON cm.community_id = c.id; -create view community_follower_view as -select +CREATE VIEW community_follower_view AS +SELECT cf.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_follower cf -left join user_ u on cf.user_id = u.id -left join community c on cf.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_follower cf + LEFT JOIN user_ u ON cf.user_id = u.id + LEFT JOIN community c ON cf.community_id = c.id; -create view community_user_ban_view as -select +CREATE VIEW community_user_ban_view AS +SELECT cb.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_user_ban cb -left join user_ u on cb.user_id = u.id -left join community c on cb.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_user_ban cb + LEFT JOIN user_ u ON cb.user_id = u.id + LEFT JOIN community c ON cb.community_id = c.id; -- The community fast table +CREATE TABLE community_aggregates_fast AS +SELECT + * +FROM + community_aggregates_view; -create table community_aggregates_fast as select * from community_aggregates_view; -alter table community_aggregates_fast add primary key (id); +ALTER TABLE community_aggregates_fast + ADD PRIMARY KEY (id); -create view community_fast_view as -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join ( - select - ca.* - from community_aggregates_fast ca -) ac +CREATE VIEW community_fast_view AS +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + community_aggregates_fast ca) ac +UNION ALL +SELECT + caf.*, + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_fast caf; -union all +DROP TRIGGER refresh_community ON community; -select -caf.*, -null as user_id, -null as subscribed -from community_aggregates_fast caf; - -drop trigger refresh_community on community; - -create trigger refresh_community -after insert or update or delete -on community -for each row -execute procedure refresh_community(); +CREATE TRIGGER refresh_community + AFTER INSERT OR UPDATE OR DELETE ON community + FOR EACH ROW + EXECUTE PROCEDURE refresh_community (); -- Sample select -- select * from community_fast_view where name like 'test_community_name' and user_id is null; --- Sample insert +-- Sample insert -- insert into community(name, title, category_id, creator_id) values ('test_community_name', 'test_community_title', 1, 2); -- Sample delete -- delete from community where name like 'test_community_name'; -- Sample update -- update community set title = 'test_community_title_2' where name like 'test_community_name'; -create or replace function refresh_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from community_aggregates_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from community_aggregates_fast where id = OLD.id; - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id; - - -- Update user view due to owner changes - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update post view due to community changes - delete from post_aggregates_fast where community_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where community_id = NEW.id; - - -- TODO make sure this shows up in the users page ? - ELSIF (TG_OP = 'INSERT') THEN - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id; - END IF; - - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to owner changes + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update post view due to community changes + DELETE FROM post_aggregates_fast + WHERE community_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + community_id = NEW.id; + -- TODO make sure this shows up in the users page ? + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; -- Comment +DROP VIEW user_mention_view; -drop view user_mention_view; -drop view comment_view; -drop view comment_aggregates_view; +DROP VIEW comment_view; -create view comment_aggregates_view as -select - ct.*, - -- community details - p.community_id, - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW comment_aggregates_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- community details + p.community_id, + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; -union all - -select +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -- The fast view -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; -- user mention -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -633,15 +811,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -665,26 +858,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -708,232 +920,345 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; +DROP TRIGGER refresh_comment ON comment; -drop trigger refresh_comment on comment; - -create trigger refresh_comment -after insert or update or delete -on comment -for each row -execute procedure refresh_comment(); +CREATE TRIGGER refresh_comment + AFTER INSERT OR UPDATE OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE refresh_comment (); -- Sample select -- select * from comment_fast_view where content = 'test_comment' and user_id is null; --- Sample insert +-- Sample insert -- insert into comment(creator_id, post_id, content) values (2, 2, 'test_comment'); -- Sample delete -- delete from comment where content like 'test_comment'; -- Sample update -- update comment set removed = true where content like 'test_comment'; -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id; - - -- Force the hot rank as zero on week-older posts - update post_aggregates_fast as paf - set hot_rank = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '1 week'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; - +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id; + -- Force the hot rank as zero on week-older posts + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '1 week'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; -- post_like -- select id, score, my_vote from post_fast_view where id = 29 and user_id = 4; --- Sample insert +-- Sample insert -- insert into post_like(user_id, post_id, score) values (4, 29, 1); -- Sample delete -- delete from post_like where user_id = 4 and post_id = 29; -- Sample update -- update post_like set score = -1 where user_id = 4 and post_id = 29; - -- TODO test this a LOT -create or replace function refresh_post_like() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - update post_aggregates_fast - set score = case - when (OLD.score = 1) then score - 1 - else score + 1 end, - upvotes = case - when (OLD.score = 1) then upvotes - 1 - else upvotes end, - downvotes = case - when (OLD.score = -1) then downvotes - 1 - else downvotes end - where id = OLD.post_id; +CREATE OR REPLACE FUNCTION refresh_post_like () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + UPDATE + post_aggregates_fast + SET + score = CASE WHEN (OLD.score = 1) THEN + score - 1 + ELSE + score + 1 + END, + upvotes = CASE WHEN (OLD.score = 1) THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN (OLD.score = - 1) THEN + downvotes - 1 + ELSE + downvotes + END + WHERE + id = OLD.post_id; + ELSIF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates_fast + SET + score = CASE WHEN (NEW.score = 1) THEN + score + 1 + ELSE + score - 1 + END, + upvotes = CASE WHEN (NEW.score = 1) THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN (NEW.score = - 1) THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'INSERT') THEN - update post_aggregates_fast - set score = case - when (NEW.score = 1) then score + 1 - else score - 1 end, - upvotes = case - when (NEW.score = 1) then upvotes + 1 - else upvotes end, - downvotes = case - when (NEW.score = -1) then downvotes + 1 - else downvotes end - where id = NEW.post_id; - END IF; +DROP TRIGGER refresh_post_like ON post_like; - return null; -end $$; - -drop trigger refresh_post_like on post_like; -create trigger refresh_post_like -after insert or delete -on post_like -for each row -execute procedure refresh_post_like(); +CREATE TRIGGER refresh_post_like + AFTER INSERT OR DELETE ON post_like + FOR EACH ROW + EXECUTE PROCEDURE refresh_post_like (); -- comment_like -- select id, score, my_vote from comment_fast_view where id = 29 and user_id = 4; --- Sample insert +-- Sample insert -- insert into comment_like(user_id, comment_id, post_id, score) values (4, 29, 51, 1); -- Sample delete -- delete from comment_like where user_id = 4 and comment_id = 29; -- Sample update -- update comment_like set score = -1 where user_id = 4 and comment_id = 29; -create or replace function refresh_comment_like() -returns trigger language plpgsql -as $$ -begin - -- TODO possibly select from comment_fast to get previous scores, instead of re-fetching the views? - IF (TG_OP = 'DELETE') THEN - update comment_aggregates_fast - set score = case - when (OLD.score = 1) then score - 1 - else score + 1 end, - upvotes = case - when (OLD.score = 1) then upvotes - 1 - else upvotes end, - downvotes = case - when (OLD.score = -1) then downvotes - 1 - else downvotes end - where id = OLD.comment_id; +CREATE OR REPLACE FUNCTION refresh_comment_like () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- TODO possibly select from comment_fast to get previous scores, instead of re-fetching the views? + IF (TG_OP = 'DELETE') THEN + UPDATE + comment_aggregates_fast + SET + score = CASE WHEN (OLD.score = 1) THEN + score - 1 + ELSE + score + 1 + END, + upvotes = CASE WHEN (OLD.score = 1) THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN (OLD.score = - 1) THEN + downvotes - 1 + ELSE + downvotes + END + WHERE + id = OLD.comment_id; + ELSIF (TG_OP = 'INSERT') THEN + UPDATE + comment_aggregates_fast + SET + score = CASE WHEN (NEW.score = 1) THEN + score + 1 + ELSE + score - 1 + END, + upvotes = CASE WHEN (NEW.score = 1) THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN (NEW.score = - 1) THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + id = NEW.comment_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'INSERT') THEN - update comment_aggregates_fast - set score = case - when (NEW.score = 1) then score + 1 - else score - 1 end, - upvotes = case - when (NEW.score = 1) then upvotes + 1 - else upvotes end, - downvotes = case - when (NEW.score = -1) then downvotes + 1 - else downvotes end - where id = NEW.comment_id; - END IF; +DROP TRIGGER refresh_comment_like ON comment_like; - return null; -end $$; - -drop trigger refresh_comment_like on comment_like; -create trigger refresh_comment_like -after insert or delete -on comment_like -for each row -execute procedure refresh_comment_like(); +CREATE TRIGGER refresh_comment_like + AFTER INSERT OR DELETE ON comment_like + FOR EACH ROW + EXECUTE PROCEDURE refresh_comment_like (); -- Community user ban +DROP TRIGGER refresh_community_user_ban ON community_user_ban; -drop trigger refresh_community_user_ban on community_user_ban; -create trigger refresh_community_user_ban -after insert or delete -- Note this is missing after update -on community_user_ban -for each row -execute procedure refresh_community_user_ban(); +CREATE TRIGGER refresh_community_user_ban + AFTER INSERT OR DELETE -- Note this is missing after update + ON community_user_ban + FOR EACH ROW + EXECUTE PROCEDURE refresh_community_user_ban (); -- select creator_name, banned_from_community from comment_fast_view where user_id = 4 and content = 'test_before_ban'; -- select creator_name, banned_from_community, community_id from comment_aggregates_fast where content = 'test_before_ban'; --- Sample insert +-- Sample insert -- insert into comment(creator_id, post_id, content) values (1198, 341, 'test_before_ban'); -- insert into community_user_ban(community_id, user_id) values (2, 1198); -- Sample delete -- delete from community_user_ban where user_id = 1198 and community_id = 2; -- delete from comment where content = 'test_before_ban'; -- update comment_aggregates_fast set banned_from_community = false where creator_id = 1198 and community_id = 2; -create or replace function refresh_community_user_ban() -returns trigger language plpgsql -as $$ -begin - -- TODO possibly select from comment_fast to get previous scores, instead of re-fetching the views? - IF (TG_OP = 'DELETE') THEN - update comment_aggregates_fast set banned_from_community = false where creator_id = OLD.user_id and community_id = OLD.community_id; - update post_aggregates_fast set banned_from_community = false where creator_id = OLD.user_id and community_id = OLD.community_id; - ELSIF (TG_OP = 'INSERT') THEN - update comment_aggregates_fast set banned_from_community = true where creator_id = NEW.user_id and community_id = NEW.community_id; - update post_aggregates_fast set banned_from_community = true where creator_id = NEW.user_id and community_id = NEW.community_id; - END IF; - - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_community_user_ban () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- TODO possibly select from comment_fast to get previous scores, instead of re-fetching the views? + IF (TG_OP = 'DELETE') THEN + UPDATE + comment_aggregates_fast + SET + banned_from_community = FALSE + WHERE + creator_id = OLD.user_id + AND community_id = OLD.community_id; + UPDATE + post_aggregates_fast + SET + banned_from_community = FALSE + WHERE + creator_id = OLD.user_id + AND community_id = OLD.community_id; + ELSIF (TG_OP = 'INSERT') THEN + UPDATE + comment_aggregates_fast + SET + banned_from_community = TRUE + WHERE + creator_id = NEW.user_id + AND community_id = NEW.community_id; + UPDATE + post_aggregates_fast + SET + banned_from_community = TRUE + WHERE + creator_id = NEW.user_id + AND community_id = NEW.community_id; + END IF; + RETURN NULL; +END +$$; -- Community follower +DROP TRIGGER refresh_community_follower ON community_follower; -drop trigger refresh_community_follower on community_follower; -create trigger refresh_community_follower -after insert or delete -- Note this is missing after update -on community_follower -for each row -execute procedure refresh_community_follower(); +CREATE TRIGGER refresh_community_follower + AFTER INSERT OR DELETE -- Note this is missing after update + ON community_follower + FOR EACH ROW + EXECUTE PROCEDURE refresh_community_follower (); -create or replace function refresh_community_follower() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - update community_aggregates_fast set number_of_subscribers = number_of_subscribers - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'INSERT') THEN - update community_aggregates_fast set number_of_subscribers = number_of_subscribers + 1 where id = NEW.community_id; - END IF; +CREATE OR REPLACE FUNCTION refresh_community_follower () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates_fast + SET + number_of_subscribers = number_of_subscribers - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates_fast + SET + number_of_subscribers = number_of_subscribers + 1 + WHERE + id = NEW.community_id; + END IF; + RETURN NULL; +END +$$; - return null; -end $$; diff --git a/migrations/2020-07-08-202609_add_creator_published/down.sql b/migrations/2020-07-08-202609_add_creator_published/down.sql index b8e4452e3..fd1ca1cb4 100644 --- a/migrations/2020-07-08-202609_add_creator_published/down.sql +++ b/migrations/2020-07-08-202609_add_creator_published/down.sql @@ -1,115 +1,145 @@ -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; +DROP VIEW user_mention_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW reply_fast_view; -create view comment_aggregates_view as -select - ct.*, - -- community details - p.community_id, - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW comment_fast_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +DROP VIEW comment_view; -union all +DROP VIEW user_mention_fast_view; -select +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- community details + p.community_id, + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; + +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -137,15 +167,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -169,26 +214,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -212,177 +276,220 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; -- add creator_published to the post view -drop view post_fast_view; -drop table post_aggregates_fast; -drop view post_view; -drop view post_aggregates_view; +DROP VIEW post_fast_view; -create view post_aggregates_view as -select - p.*, - -- creator details - u.actor_id as creator_actor_id, - u."local" as creator_local, - u."name" as creator_name, - u.avatar as creator_avatar, - u.banned as banned, - cb.id::bool as banned_from_community, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.removed as community_removed, - c.deleted as community_deleted, - c.nsfw as community_nsfw, - -- post score data/comment count - coalesce(ct.comments, 0) as number_of_comments, - coalesce(pl.score, 0) as score, - coalesce(pl.upvotes, 0) as upvotes, - coalesce(pl.downvotes, 0) as downvotes, - hot_rank( - coalesce(pl.score , 0), ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) - ) as hot_rank, - ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) as newest_activity_time -from post p -left join user_ u on p.creator_id = u.id -left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id -left join community c on p.community_id = c.id -left join ( - select - post_id, - count(*) as comments, - max(published) as recent_comment_time - from comment - group by post_id -) ct on ct.post_id = p.id -left join ( - select - post_id, - sum(score) as score, - sum(score) filter (where score = 1) as upvotes, - -sum(score) filter (where score = -1) as downvotes - from post_like - group by post_id -) pl on pl.post_id = p.id -order by p.id; +DROP TABLE post_aggregates_fast; -create view post_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_view pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +DROP VIEW post_view; -union all +DROP VIEW post_aggregates_view; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_view pav; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + -- creator details + u.actor_id AS creator_actor_id, + u."local" AS creator_local, + u."name" AS creator_name, + u.avatar AS creator_avatar, + u.banned AS banned, + cb.id::bool AS banned_from_community, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.removed AS community_removed, + c.deleted AS community_deleted, + c.nsfw AS community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) AS number_of_comments, + coalesce(pl.score, 0) AS score, + coalesce(pl.upvotes, 0) AS upvotes, + coalesce(pl.downvotes, 0) AS downvotes, + hot_rank (coalesce(pl.score, 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN user_ u ON p.creator_id = u.id + LEFT JOIN community_user_ban cb ON p.creator_id = cb.user_id + AND p.community_id = cb.community_id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN ( + SELECT + post_id, + count(*) AS comments, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_id, + sum(score) AS score, + sum(score) FILTER (WHERE score = 1) AS upvotes, + - sum(score) FILTER (WHERE score = - 1) AS downvotes + FROM + post_like + GROUP BY + post_id) pl ON pl.post_id = p.id +ORDER BY + p.id; -create table post_aggregates_fast as select * from post_aggregates_view; -alter table post_aggregates_fast add primary key (id); +CREATE VIEW post_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_view pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_view pav; -create view post_fast_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_fast pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE TABLE post_aggregates_fast AS +SELECT + * +FROM + post_aggregates_view; -union all +ALTER TABLE post_aggregates_fast + ADD PRIMARY KEY (id); + +CREATE VIEW post_fast_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_fast pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_fast pav; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_fast pav; \ No newline at end of file diff --git a/migrations/2020-07-08-202609_add_creator_published/up.sql b/migrations/2020-07-08-202609_add_creator_published/up.sql index 1f2b59ea9..6d3ff57d0 100644 --- a/migrations/2020-07-08-202609_add_creator_published/up.sql +++ b/migrations/2020-07-08-202609_add_creator_published/up.sql @@ -1,116 +1,146 @@ -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; +DROP VIEW user_mention_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW reply_fast_view; -create view comment_aggregates_view as -select - ct.*, - -- community details - p.community_id, - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW comment_fast_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +DROP VIEW comment_view; -union all +DROP VIEW user_mention_fast_view; -select +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- community details + p.community_id, + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; + +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -138,15 +168,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -170,26 +215,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -213,178 +277,221 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; -- add creator_published to the post view -drop view post_fast_view; -drop table post_aggregates_fast; -drop view post_view; -drop view post_aggregates_view; +DROP VIEW post_fast_view; -create view post_aggregates_view as -select - p.*, - -- creator details - u.actor_id as creator_actor_id, - u."local" as creator_local, - u."name" as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - u.banned as banned, - cb.id::bool as banned_from_community, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.removed as community_removed, - c.deleted as community_deleted, - c.nsfw as community_nsfw, - -- post score data/comment count - coalesce(ct.comments, 0) as number_of_comments, - coalesce(pl.score, 0) as score, - coalesce(pl.upvotes, 0) as upvotes, - coalesce(pl.downvotes, 0) as downvotes, - hot_rank( - coalesce(pl.score , 0), ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) - ) as hot_rank, - ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) as newest_activity_time -from post p -left join user_ u on p.creator_id = u.id -left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id -left join community c on p.community_id = c.id -left join ( - select - post_id, - count(*) as comments, - max(published) as recent_comment_time - from comment - group by post_id -) ct on ct.post_id = p.id -left join ( - select - post_id, - sum(score) as score, - sum(score) filter (where score = 1) as upvotes, - -sum(score) filter (where score = -1) as downvotes - from post_like - group by post_id -) pl on pl.post_id = p.id -order by p.id; +DROP TABLE post_aggregates_fast; -create view post_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_view pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +DROP VIEW post_view; -union all +DROP VIEW post_aggregates_view; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_view pav; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + -- creator details + u.actor_id AS creator_actor_id, + u."local" AS creator_local, + u."name" AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + u.banned AS banned, + cb.id::bool AS banned_from_community, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.removed AS community_removed, + c.deleted AS community_deleted, + c.nsfw AS community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) AS number_of_comments, + coalesce(pl.score, 0) AS score, + coalesce(pl.upvotes, 0) AS upvotes, + coalesce(pl.downvotes, 0) AS downvotes, + hot_rank (coalesce(pl.score, 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN user_ u ON p.creator_id = u.id + LEFT JOIN community_user_ban cb ON p.creator_id = cb.user_id + AND p.community_id = cb.community_id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN ( + SELECT + post_id, + count(*) AS comments, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_id, + sum(score) AS score, + sum(score) FILTER (WHERE score = 1) AS upvotes, + - sum(score) FILTER (WHERE score = - 1) AS downvotes + FROM + post_like + GROUP BY + post_id) pl ON pl.post_id = p.id +ORDER BY + p.id; -create table post_aggregates_fast as select * from post_aggregates_view; -alter table post_aggregates_fast add primary key (id); +CREATE VIEW post_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_view pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_view pav; -create view post_fast_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_fast pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE TABLE post_aggregates_fast AS +SELECT + * +FROM + post_aggregates_view; -union all +ALTER TABLE post_aggregates_fast + ADD PRIMARY KEY (id); + +CREATE VIEW post_fast_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_fast pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_fast pav; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_fast pav; \ No newline at end of file diff --git a/migrations/2020-07-12-100442_add_post_title_to_comments_view/down.sql b/migrations/2020-07-12-100442_add_post_title_to_comments_view/down.sql index b7c9d51ef..b29521b4d 100644 --- a/migrations/2020-07-12-100442_add_post_title_to_comments_view/down.sql +++ b/migrations/2020-07-12-100442_add_post_title_to_comments_view/down.sql @@ -1,116 +1,146 @@ -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; +DROP VIEW user_mention_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW reply_fast_view; -create view comment_aggregates_view as -select - ct.*, - -- community details - p.community_id, - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW comment_fast_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +DROP VIEW comment_view; -union all +DROP VIEW user_mention_fast_view; -select +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- community details + p.community_id, + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; + +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -138,15 +168,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -170,26 +215,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -213,37 +277,60 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; \ No newline at end of file +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; + diff --git a/migrations/2020-07-12-100442_add_post_title_to_comments_view/up.sql b/migrations/2020-07-12-100442_add_post_title_to_comments_view/up.sql index 4cfa7edbc..aef427335 100644 --- a/migrations/2020-07-12-100442_add_post_title_to_comments_view/up.sql +++ b/migrations/2020-07-12-100442_add_post_title_to_comments_view/up.sql @@ -1,118 +1,148 @@ -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; +DROP VIEW user_mention_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW reply_fast_view; -create view comment_aggregates_view as -select - ct.*, - -- post details - p."name" as post_name, - p.community_id, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW comment_fast_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +DROP VIEW comment_view; -union all +DROP VIEW user_mention_fast_view; -select +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- post details + p."name" AS post_name, + p.community_id, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; + +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -141,15 +171,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -174,26 +219,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -218,37 +282,60 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; \ No newline at end of file +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; + diff --git a/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/down.sql b/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/down.sql index 7a4f2e2f1..e74da33d1 100644 --- a/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/down.sql +++ b/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/down.sql @@ -1,20 +1,34 @@ +ALTER TABLE community + ALTER COLUMN actor_id SET NOT NULL; -alter table community alter column actor_id set not null; -alter table community alter column actor_id set default 'http://fake.com'; -alter table user_ alter column actor_id set not null; -alter table user_ alter column actor_id set default 'http://fake.com'; +ALTER TABLE community + ALTER COLUMN actor_id SET DEFAULT 'http://fake.com'; -drop function generate_unique_changeme; +ALTER TABLE user_ + ALTER COLUMN actor_id SET NOT NULL; -update community -set actor_id = 'http://fake.com' -where actor_id like 'changeme_%'; +ALTER TABLE user_ + ALTER COLUMN actor_id SET DEFAULT 'http://fake.com'; -update user_ -set actor_id = 'http://fake.com' -where actor_id like 'changeme_%'; +DROP FUNCTION generate_unique_changeme; -drop index idx_user_lower_actor_id; -create unique index idx_user_name_lower_actor_id on user_ (lower(name), lower(actor_id)); +UPDATE + community +SET + actor_id = 'http://fake.com' +WHERE + actor_id LIKE 'changeme_%'; + +UPDATE + user_ +SET + actor_id = 'http://fake.com' +WHERE + actor_id LIKE 'changeme_%'; + +DROP INDEX idx_user_lower_actor_id; + +CREATE UNIQUE INDEX idx_user_name_lower_actor_id ON user_ (lower(name), lower(actor_id)); + +DROP INDEX idx_community_lower_actor_id; -drop index idx_community_lower_actor_id; diff --git a/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/up.sql b/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/up.sql index e32ed5e08..527c73b1e 100644 --- a/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/up.sql +++ b/migrations/2020-07-18-234519_add_unique_community_user_actor_ids/up.sql @@ -1,50 +1,78 @@ -- Following this issue : https://github.com/LemmyNet/lemmy/issues/957 - -- Creating a unique changeme actor_id -create or replace function generate_unique_changeme() -returns text language sql -as $$ - select 'changeme_' || string_agg (substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil (random() * 62)::integer, 1), '') - from generate_series(1, 20) +CREATE OR REPLACE FUNCTION generate_unique_changeme () + RETURNS text + LANGUAGE sql + AS $$ + SELECT + 'changeme_' || string_agg(substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil(random() * 62)::integer, 1), '') + FROM + generate_series(1, 20) $$; -- Need to delete the possible community and user dupes for ones that don't start with the fake one -- A few test inserts, to make sure this removes later dupes -- insert into community (name, title, category_id, creator_id) values ('testcom', 'another testcom', 1, 2); -delete from community a using ( - select min(id) as id, actor_id - from community - group by actor_id having count(*) > 1 -) b -where a.actor_id = b.actor_id -and a.id <> b.id; +DELETE FROM community a USING ( + SELECT + min(id) AS id, + actor_id + FROM + community + GROUP BY + actor_id + HAVING + count(*) > 1) b +WHERE + a.actor_id = b.actor_id + AND a.id <> b.id; -delete from user_ a using ( - select min(id) as id, actor_id - from user_ - group by actor_id having count(*) > 1 -) b -where a.actor_id = b.actor_id -and a.id <> b.id; +DELETE FROM user_ a USING ( + SELECT + min(id) AS id, + actor_id + FROM + user_ + GROUP BY + actor_id + HAVING + count(*) > 1) b +WHERE + a.actor_id = b.actor_id + AND a.id <> b.id; -- Replacing the current default on the columns, to the unique one -update community -set actor_id = generate_unique_changeme() -where actor_id = 'http://fake.com'; +UPDATE + community +SET + actor_id = generate_unique_changeme () +WHERE + actor_id = 'http://fake.com'; -update user_ -set actor_id = generate_unique_changeme() -where actor_id = 'http://fake.com'; +UPDATE + user_ +SET + actor_id = generate_unique_changeme () +WHERE + actor_id = 'http://fake.com'; -- Add the unique indexes -alter table community alter column actor_id set not null; -alter table community alter column actor_id set default generate_unique_changeme(); +ALTER TABLE community + ALTER COLUMN actor_id SET NOT NULL; -alter table user_ alter column actor_id set not null; -alter table user_ alter column actor_id set default generate_unique_changeme(); +ALTER TABLE community + ALTER COLUMN actor_id SET DEFAULT generate_unique_changeme (); + +ALTER TABLE user_ + ALTER COLUMN actor_id SET NOT NULL; + +ALTER TABLE user_ + ALTER COLUMN actor_id SET DEFAULT generate_unique_changeme (); -- Add lowercase uniqueness too -drop index idx_user_name_lower_actor_id; -create unique index idx_user_lower_actor_id on user_ (lower(actor_id)); +DROP INDEX idx_user_name_lower_actor_id; + +CREATE UNIQUE INDEX idx_user_lower_actor_id ON user_ (lower(actor_id)); + +CREATE UNIQUE INDEX idx_community_lower_actor_id ON community (lower(actor_id)); -create unique index idx_community_lower_actor_id on community (lower(actor_id)); diff --git a/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/down.sql b/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/down.sql index 8ac1a99c9..cb04cdd6a 100644 --- a/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/down.sql +++ b/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/down.sql @@ -1,231 +1,308 @@ -- Drops first -drop view site_view; -drop table user_fast; -drop view user_view; -drop view post_fast_view; -drop table post_aggregates_fast; -drop view post_view; -drop view post_aggregates_view; -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view community_view; -drop view community_aggregates_view; -drop view community_fast_view; -drop table community_aggregates_fast; -drop view private_message_view; -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW site_view; -alter table site - drop column icon, - drop column banner; +DROP TABLE user_fast; -alter table community - drop column icon, - drop column banner; +DROP VIEW user_view; -alter table user_ drop column banner; +DROP VIEW post_fast_view; + +DROP TABLE post_aggregates_fast; + +DROP VIEW post_view; + +DROP VIEW post_aggregates_view; + +DROP VIEW community_moderator_view; + +DROP VIEW community_follower_view; + +DROP VIEW community_user_ban_view; + +DROP VIEW community_view; + +DROP VIEW community_aggregates_view; + +DROP VIEW community_fast_view; + +DROP TABLE community_aggregates_fast; + +DROP VIEW private_message_view; + +DROP VIEW user_mention_view; + +DROP VIEW reply_fast_view; + +DROP VIEW comment_fast_view; + +DROP VIEW comment_view; + +DROP VIEW user_mention_fast_view; + +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +ALTER TABLE site + DROP COLUMN icon, + DROP COLUMN banner; + +ALTER TABLE community + DROP COLUMN icon, + DROP COLUMN banner; + +ALTER TABLE user_ + DROP COLUMN banner; -- Site -create view site_view as -select *, -(select name from user_ u where s.creator_id = u.id) as creator_name, -(select avatar from user_ u where s.creator_id = u.id) as creator_avatar, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s; +CREATE VIEW site_view AS +SELECT + *, + ( + SELECT + name + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_name, + ( + SELECT + avatar + FROM + user_ u + WHERE + s.creator_id = u.id) AS creator_avatar, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s; -- User -create view user_view as -select - u.id, - u.actor_id, - u.name, - u.avatar, - u.email, - u.matrix_user_id, - u.bio, - u.local, - u.admin, - u.banned, - u.show_avatars, - u.send_notifications_to_email, - u.published, - coalesce(pd.posts, 0) as number_of_posts, - coalesce(pd.score, 0) as post_score, - coalesce(cd.comments, 0) as number_of_comments, - coalesce(cd.score, 0) as comment_score -from user_ u -left join ( - select - p.creator_id as creator_id, - count(distinct p.id) as posts, - sum(pl.score) as score - from post p - join post_like pl on p.id = pl.post_id - group by p.creator_id -) pd on u.id = pd.creator_id -left join ( - select - c.creator_id, - count(distinct c.id) as comments, - sum(cl.score) as score - from comment c - join comment_like cl on c.id = cl.comment_id - group by c.creator_id -) cd on u.id = cd.creator_id; +CREATE VIEW user_view AS +SELECT + u.id, + u.actor_id, + u.name, + u.avatar, + u.email, + u.matrix_user_id, + u.bio, + u.local, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + coalesce(pd.posts, 0) AS number_of_posts, + coalesce(pd.score, 0) AS post_score, + coalesce(cd.comments, 0) AS number_of_comments, + coalesce(cd.score, 0) AS comment_score +FROM + user_ u + LEFT JOIN ( + SELECT + p.creator_id AS creator_id, + count(DISTINCT p.id) AS posts, + sum(pl.score) AS score + FROM + post p + JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.creator_id) pd ON u.id = pd.creator_id + LEFT JOIN ( + SELECT + c.creator_id, + count(DISTINCT c.id) AS comments, + sum(cl.score) AS score + FROM + comment c + JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.creator_id) cd ON u.id = cd.creator_id; -create table user_fast as select * from user_view; -alter table user_fast add primary key (id); +CREATE TABLE user_fast AS +SELECT + * +FROM + user_view; + +ALTER TABLE user_fast + ADD PRIMARY KEY (id); -- Post fast +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + -- creator details + u.actor_id AS creator_actor_id, + u."local" AS creator_local, + u."name" AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + u.banned AS banned, + cb.id::bool AS banned_from_community, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.removed AS community_removed, + c.deleted AS community_deleted, + c.nsfw AS community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) AS number_of_comments, + coalesce(pl.score, 0) AS score, + coalesce(pl.upvotes, 0) AS upvotes, + coalesce(pl.downvotes, 0) AS downvotes, + hot_rank (coalesce(pl.score, 0), ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END)) AS hot_rank, + ( + CASE WHEN (p.published < ('now'::timestamp - '1 month'::interval)) THEN + p.published + ELSE + greatest (ct.recent_comment_time, p.published) + END) AS newest_activity_time +FROM + post p + LEFT JOIN user_ u ON p.creator_id = u.id + LEFT JOIN community_user_ban cb ON p.creator_id = cb.user_id + AND p.community_id = cb.community_id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN ( + SELECT + post_id, + count(*) AS comments, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_id, + sum(score) AS score, + sum(score) FILTER (WHERE score = 1) AS upvotes, + - sum(score) FILTER (WHERE score = - 1) AS downvotes + FROM + post_like + GROUP BY + post_id) pl ON pl.post_id = p.id +ORDER BY + p.id; -create view post_aggregates_view as -select - p.*, - -- creator details - u.actor_id as creator_actor_id, - u."local" as creator_local, - u."name" as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - u.banned as banned, - cb.id::bool as banned_from_community, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.removed as community_removed, - c.deleted as community_deleted, - c.nsfw as community_nsfw, - -- post score data/comment count - coalesce(ct.comments, 0) as number_of_comments, - coalesce(pl.score, 0) as score, - coalesce(pl.upvotes, 0) as upvotes, - coalesce(pl.downvotes, 0) as downvotes, - hot_rank( - coalesce(pl.score , 0), ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) - ) as hot_rank, - ( - case - when (p.published < ('now'::timestamp - '1 month'::interval)) - then p.published - else greatest(ct.recent_comment_time, p.published) - end - ) as newest_activity_time -from post p -left join user_ u on p.creator_id = u.id -left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id -left join community c on p.community_id = c.id -left join ( - select - post_id, - count(*) as comments, - max(published) as recent_comment_time - from comment - group by post_id -) ct on ct.post_id = p.id -left join ( - select - post_id, - sum(score) as score, - sum(score) filter (where score = 1) as upvotes, - -sum(score) filter (where score = -1) as downvotes - from post_like - group by post_id -) pl on pl.post_id = p.id -order by p.id; +CREATE VIEW post_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_view pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_view pav; -create view post_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_view pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE TABLE post_aggregates_fast AS +SELECT + * +FROM + post_aggregates_view; -union all +ALTER TABLE post_aggregates_fast + ADD PRIMARY KEY (id); -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_view pav; - -create table post_aggregates_fast as select * from post_aggregates_view; -alter table post_aggregates_fast add primary key (id); - -create view post_fast_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_fast pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us - -union all - -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_fast pav; +CREATE VIEW post_fast_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_fast pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_fast pav; -- Community -create view community_aggregates_view as -select +CREATE VIEW community_aggregates_view AS +SELECT c.id, c.name, c.title, @@ -240,250 +317,292 @@ select c.actor_id, c.local, c.last_refreshed_at, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.avatar as creator_avatar, - cat.name as category_name, - coalesce(cf.subs, 0) as number_of_subscribers, - coalesce(cd.posts, 0) as number_of_posts, - coalesce(cd.comments, 0) as number_of_comments, - hot_rank(cf.subs, c.published) as hot_rank -from community c -left join user_ u on c.creator_id = u.id -left join category cat on c.category_id = cat.id -left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - join comment ct on p.id = ct.post_id - group by p.community_id -) cd on cd.community_id = c.id -left join ( - select - community_id, - count(*) as subs - from community_follower - group by community_id -) cf on cf.community_id = c.id; + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.avatar AS creator_avatar, + cat.name AS category_name, + coalesce(cf.subs, 0) AS number_of_subscribers, + coalesce(cd.posts, 0) AS number_of_posts, + coalesce(cd.comments, 0) AS number_of_comments, + hot_rank (cf.subs, c.published) AS hot_rank +FROM + community c + LEFT JOIN user_ u ON c.creator_id = u.id + LEFT JOIN category cat ON c.category_id = cat.id + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_id) cf ON cf.community_id = c.id; -create view community_view as -select +CREATE VIEW community_view AS +SELECT cv.*, - us.user as user_id, - us.is_subbed::bool as subscribed -from community_aggregates_view cv -cross join lateral ( - select - u.id as user, - coalesce(cf.community_id, 0) as is_subbed - from user_ u - left join community_follower cf on u.id = cf.user_id and cf.community_id = cv.id -) as us - -union all - -select + us.user AS user_id, + us.is_subbed::bool AS subscribed +FROM + community_aggregates_view cv + CROSS JOIN LATERAL ( + SELECT + u.id AS user, + coalesce(cf.community_id, 0) AS is_subbed + FROM + user_ u + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = cv.id) AS us +UNION ALL +SELECT cv.*, - null as user_id, - null as subscribed -from community_aggregates_view cv; + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_view cv; -create view community_moderator_view as -select +CREATE VIEW community_moderator_view AS +SELECT cm.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_moderator cm -left join user_ u on cm.user_id = u.id -left join community c on cm.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_moderator cm + LEFT JOIN user_ u ON cm.user_id = u.id + LEFT JOIN community c ON cm.community_id = c.id; -create view community_follower_view as -select +CREATE VIEW community_follower_view AS +SELECT cf.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_follower cf -left join user_ u on cf.user_id = u.id -left join community c on cf.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_follower cf + LEFT JOIN user_ u ON cf.user_id = u.id + LEFT JOIN community c ON cf.community_id = c.id; -create view community_user_ban_view as -select +CREATE VIEW community_user_ban_view AS +SELECT cb.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name -from community_user_ban cb -left join user_ u on cb.user_id = u.id -left join community c on cb.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name +FROM + community_user_ban cb + LEFT JOIN user_ u ON cb.user_id = u.id + LEFT JOIN community c ON cb.community_id = c.id; -- The community fast table +CREATE TABLE community_aggregates_fast AS +SELECT + * +FROM + community_aggregates_view; -create table community_aggregates_fast as select * from community_aggregates_view; -alter table community_aggregates_fast add primary key (id); - -create view community_fast_view as -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join ( - select - ca.* - from community_aggregates_fast ca -) ac - -union all - -select -caf.*, -null as user_id, -null as subscribed -from community_aggregates_fast caf; +ALTER TABLE community_aggregates_fast + ADD PRIMARY KEY (id); +CREATE VIEW community_fast_view AS +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + community_aggregates_fast ca) ac +UNION ALL +SELECT + caf.*, + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_fast caf; -- Private message -create view private_message_view as -select -pm.*, -u.name as creator_name, -u.avatar as creator_avatar, -u.actor_id as creator_actor_id, -u.local as creator_local, -u2.name as recipient_name, -u2.avatar as recipient_avatar, -u2.actor_id as recipient_actor_id, -u2.local as recipient_local -from private_message pm -inner join user_ u on u.id = pm.creator_id -inner join user_ u2 on u2.id = pm.recipient_id; - +CREATE VIEW private_message_view AS +SELECT + pm.*, + u.name AS creator_name, + u.avatar AS creator_avatar, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u2.name AS recipient_name, + u2.avatar AS recipient_avatar, + u2.actor_id AS recipient_actor_id, + u2.local AS recipient_local +FROM + private_message pm + INNER JOIN user_ u ON u.id = pm.creator_id + INNER JOIN user_ u2 ON u2.id = pm.recipient_id; -- Comments, mentions, replies +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- post details + p."name" AS post_name, + p.community_id, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.published AS creator_published, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 0), ct.published) AS hot_rank +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; -create view comment_aggregates_view as -select - ct.*, - -- post details - p."name" as post_name, - p.community_id, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.published as creator_published, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; - -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us - -union all - -select +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -512,15 +631,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -545,26 +679,45 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -589,116 +742,204 @@ select ac.upvotes, ac.downvotes, ac.hot_rank, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; -- redoing the triggers -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id; + -- Force the hot rank as zero on week-older posts + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '1 week'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set hot_rank = pav.hot_rank - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id; - - -- Force the hot rank as zero on week-older posts - update post_aggregates_fast as paf - set hot_rank = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '1 week'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; diff --git a/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/up.sql b/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/up.sql index 97f35fb0e..7293de205 100644 --- a/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/up.sql +++ b/migrations/2020-08-03-000110_add_preferred_usernames_banners_and_icons/up.sql @@ -5,243 +5,305 @@ -- Community Banner -- User Banner (User avatar is already there) -- User preferred name (already in table, needs to be added to view) - -- It also adds hot_rank_active to post_view +ALTER TABLE site + ADD COLUMN icon text, + ADD COLUMN banner text; -alter table site - add column icon text, - add column banner text; +ALTER TABLE community + ADD COLUMN icon text, + ADD COLUMN banner text; -alter table community - add column icon text, - add column banner text; +ALTER TABLE user_ + ADD COLUMN banner text; -alter table user_ add column banner text; +DROP VIEW site_view; -drop view site_view; -create view site_view as -select s.*, -u.name as creator_name, -u.preferred_username as creator_preferred_username, -u.avatar as creator_avatar, -(select count(*) from user_) as number_of_users, -(select count(*) from post) as number_of_posts, -(select count(*) from comment) as number_of_comments, -(select count(*) from community) as number_of_communities -from site s -left join user_ u on s.creator_id = u.id; +CREATE VIEW site_view AS +SELECT + s.*, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.avatar AS creator_avatar, + ( + SELECT + count(*) + FROM + user_) AS number_of_users, + ( + SELECT + count(*) + FROM + post) AS number_of_posts, + ( + SELECT + count(*) + FROM + comment) AS number_of_comments, + ( + SELECT + count(*) + FROM + community) AS number_of_communities +FROM + site s + LEFT JOIN user_ u ON s.creator_id = u.id; -- User -drop table user_fast; -drop view user_view; -create view user_view as -select - u.id, - u.actor_id, - u.name, - u.preferred_username, - u.avatar, - u.banner, - u.email, - u.matrix_user_id, - u.bio, - u.local, - u.admin, - u.banned, - u.show_avatars, - u.send_notifications_to_email, - u.published, - coalesce(pd.posts, 0) as number_of_posts, - coalesce(pd.score, 0) as post_score, - coalesce(cd.comments, 0) as number_of_comments, - coalesce(cd.score, 0) as comment_score -from user_ u -left join ( - select - p.creator_id as creator_id, - count(distinct p.id) as posts, - sum(pl.score) as score - from post p - join post_like pl on p.id = pl.post_id - group by p.creator_id -) pd on u.id = pd.creator_id -left join ( - select - c.creator_id, - count(distinct c.id) as comments, - sum(cl.score) as score - from comment c - join comment_like cl on c.id = cl.comment_id - group by c.creator_id -) cd on u.id = cd.creator_id; +DROP TABLE user_fast; -create table user_fast as select * from user_view; -alter table user_fast add primary key (id); +DROP VIEW user_view; + +CREATE VIEW user_view AS +SELECT + u.id, + u.actor_id, + u.name, + u.preferred_username, + u.avatar, + u.banner, + u.email, + u.matrix_user_id, + u.bio, + u.local, + u.admin, + u.banned, + u.show_avatars, + u.send_notifications_to_email, + u.published, + coalesce(pd.posts, 0) AS number_of_posts, + coalesce(pd.score, 0) AS post_score, + coalesce(cd.comments, 0) AS number_of_comments, + coalesce(cd.score, 0) AS comment_score +FROM + user_ u + LEFT JOIN ( + SELECT + p.creator_id AS creator_id, + count(DISTINCT p.id) AS posts, + sum(pl.score) AS score + FROM + post p + JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.creator_id) pd ON u.id = pd.creator_id + LEFT JOIN ( + SELECT + c.creator_id, + count(DISTINCT c.id) AS comments, + sum(cl.score) AS score + FROM + comment c + JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.creator_id) cd ON u.id = cd.creator_id; + +CREATE TABLE user_fast AS +SELECT + * +FROM + user_view; + +ALTER TABLE user_fast + ADD PRIMARY KEY (id); -- private message -drop view private_message_view; -create view private_message_view as -select -pm.*, -u.name as creator_name, -u.preferred_username as creator_preferred_username, -u.avatar as creator_avatar, -u.actor_id as creator_actor_id, -u.local as creator_local, -u2.name as recipient_name, -u2.preferred_username as recipient_preferred_username, -u2.avatar as recipient_avatar, -u2.actor_id as recipient_actor_id, -u2.local as recipient_local -from private_message pm -inner join user_ u on u.id = pm.creator_id -inner join user_ u2 on u2.id = pm.recipient_id; +DROP VIEW private_message_view; + +CREATE VIEW private_message_view AS +SELECT + pm.*, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.avatar AS creator_avatar, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u2.name AS recipient_name, + u2.preferred_username AS recipient_preferred_username, + u2.avatar AS recipient_avatar, + u2.actor_id AS recipient_actor_id, + u2.local AS recipient_local +FROM + private_message pm + INNER JOIN user_ u ON u.id = pm.creator_id + INNER JOIN user_ u2 ON u2.id = pm.recipient_id; -- Post fast -drop view post_fast_view; -drop table post_aggregates_fast; -drop view post_view; -drop view post_aggregates_view; +DROP VIEW post_fast_view; -create view post_aggregates_view as -select - p.*, - -- creator details - u.actor_id as creator_actor_id, - u."local" as creator_local, - u."name" as creator_name, - u."preferred_username" as creator_preferred_username, - u.published as creator_published, - u.avatar as creator_avatar, - u.banned as banned, - cb.id::bool as banned_from_community, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.icon as community_icon, - c.removed as community_removed, - c.deleted as community_deleted, - c.nsfw as community_nsfw, - -- post score data/comment count - coalesce(ct.comments, 0) as number_of_comments, - coalesce(pl.score, 0) as score, - coalesce(pl.upvotes, 0) as upvotes, - coalesce(pl.downvotes, 0) as downvotes, - hot_rank(coalesce(pl.score, 1), p.published) as hot_rank, - hot_rank(coalesce(pl.score, 1), greatest(ct.recent_comment_time, p.published)) as hot_rank_active, - greatest(ct.recent_comment_time, p.published) as newest_activity_time -from post p -left join user_ u on p.creator_id = u.id -left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id -left join community c on p.community_id = c.id -left join ( - select - post_id, - count(*) as comments, - max(published) as recent_comment_time - from comment - group by post_id -) ct on ct.post_id = p.id -left join ( - select - post_id, - sum(score) as score, - sum(score) filter (where score = 1) as upvotes, - -sum(score) filter (where score = -1) as downvotes - from post_like - group by post_id -) pl on pl.post_id = p.id -order by p.id; +DROP TABLE post_aggregates_fast; -create view post_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_view pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +DROP VIEW post_view; -union all +DROP VIEW post_aggregates_view; -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_view pav; +CREATE VIEW post_aggregates_view AS +SELECT + p.*, + -- creator details + u.actor_id AS creator_actor_id, + u."local" AS creator_local, + u."name" AS creator_name, + u."preferred_username" AS creator_preferred_username, + u.published AS creator_published, + u.avatar AS creator_avatar, + u.banned AS banned, + cb.id::bool AS banned_from_community, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.icon AS community_icon, + c.removed AS community_removed, + c.deleted AS community_deleted, + c.nsfw AS community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) AS number_of_comments, + coalesce(pl.score, 0) AS score, + coalesce(pl.upvotes, 0) AS upvotes, + coalesce(pl.downvotes, 0) AS downvotes, + hot_rank (coalesce(pl.score, 1), p.published) AS hot_rank, + hot_rank (coalesce(pl.score, 1), greatest (ct.recent_comment_time, p.published)) AS hot_rank_active, + greatest (ct.recent_comment_time, p.published) AS newest_activity_time +FROM + post p + LEFT JOIN user_ u ON p.creator_id = u.id + LEFT JOIN community_user_ban cb ON p.creator_id = cb.user_id + AND p.community_id = cb.community_id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN ( + SELECT + post_id, + count(*) AS comments, + max(published) AS recent_comment_time + FROM + comment + GROUP BY + post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_id, + sum(score) AS score, + sum(score) FILTER (WHERE score = 1) AS upvotes, + - sum(score) FILTER (WHERE score = - 1) AS downvotes + FROM + post_like + GROUP BY + post_id) pl ON pl.post_id = p.id +ORDER BY + p.id; -create table post_aggregates_fast as select * from post_aggregates_view; -alter table post_aggregates_fast add primary key (id); +CREATE VIEW post_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_view pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_view pav; + +CREATE TABLE post_aggregates_fast AS +SELECT + * +FROM + post_aggregates_view; + +ALTER TABLE post_aggregates_fast + ADD PRIMARY KEY (id); -- For the hot rank resorting -create index idx_post_aggregates_fast_hot_rank_published on post_aggregates_fast (hot_rank desc, published desc); -create index idx_post_aggregates_fast_hot_rank_active_published on post_aggregates_fast (hot_rank_active desc, published desc); +CREATE INDEX idx_post_aggregates_fast_hot_rank_published ON post_aggregates_fast (hot_rank DESC, published DESC); -create view post_fast_view as -select - pav.*, - us.id as user_id, - us.user_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_read::bool as read, - us.is_saved::bool as saved -from post_aggregates_fast pav -cross join lateral ( - select - u.id, - coalesce(cf.community_id, 0) as is_subbed, - coalesce(pr.post_id, 0) as is_read, - coalesce(ps.post_id, 0) as is_saved, - coalesce(pl.score, 0) as user_vote - from user_ u - left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id - left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id - left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id - left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id - left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id -) as us +CREATE INDEX idx_post_aggregates_fast_hot_rank_active_published ON post_aggregates_fast (hot_rank_active DESC, published DESC); -union all - -select -pav.*, -null as user_id, -null as my_vote, -null as subscribed, -null as read, -null as saved -from post_aggregates_fast pav; +CREATE VIEW post_fast_view AS +SELECT + pav.*, + us.id AS user_id, + us.user_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_read::bool AS read, + us.is_saved::bool AS saved +FROM + post_aggregates_fast pav + CROSS JOIN LATERAL ( + SELECT + u.id, + coalesce(cf.community_id, 0) AS is_subbed, + coalesce(pr.post_id, 0) AS is_read, + coalesce(ps.post_id, 0) AS is_saved, + coalesce(pl.score, 0) AS user_vote + FROM + user_ u + LEFT JOIN community_user_ban cb ON u.id = cb.user_id + AND cb.community_id = pav.community_id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = pav.community_id + LEFT JOIN post_read pr ON u.id = pr.user_id + AND pr.post_id = pav.id + LEFT JOIN post_saved ps ON u.id = ps.user_id + AND ps.post_id = pav.id + LEFT JOIN post_like pl ON u.id = pl.user_id + AND pav.id = pl.post_id) AS us +UNION ALL +SELECT + pav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS read, + NULL AS saved +FROM + post_aggregates_fast pav; -- Community -drop view community_moderator_view; -drop view community_follower_view; -drop view community_user_ban_view; -drop view community_view; -drop view community_aggregates_view; -drop view community_fast_view; -drop table community_aggregates_fast; +DROP VIEW community_moderator_view; -create view community_aggregates_view as -select +DROP VIEW community_follower_view; + +DROP VIEW community_user_ban_view; + +DROP VIEW community_view; + +DROP VIEW community_aggregates_view; + +DROP VIEW community_fast_view; + +DROP TABLE community_aggregates_fast; + +CREATE VIEW community_aggregates_view AS +SELECT c.id, c.name, c.title, @@ -258,249 +320,299 @@ select c.actor_id, c.local, c.last_refreshed_at, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.preferred_username as creator_preferred_username, - u.avatar as creator_avatar, - cat.name as category_name, - coalesce(cf.subs, 0) as number_of_subscribers, - coalesce(cd.posts, 0) as number_of_posts, - coalesce(cd.comments, 0) as number_of_comments, - hot_rank(cf.subs, c.published) as hot_rank -from community c -left join user_ u on c.creator_id = u.id -left join category cat on c.category_id = cat.id -left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - join comment ct on p.id = ct.post_id - group by p.community_id -) cd on cd.community_id = c.id -left join ( - select - community_id, - count(*) as subs - from community_follower - group by community_id -) cf on cf.community_id = c.id; + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.avatar AS creator_avatar, + cat.name AS category_name, + coalesce(cf.subs, 0) AS number_of_subscribers, + coalesce(cd.posts, 0) AS number_of_posts, + coalesce(cd.comments, 0) AS number_of_comments, + hot_rank (cf.subs, c.published) AS hot_rank +FROM + community c + LEFT JOIN user_ u ON c.creator_id = u.id + LEFT JOIN category cat ON c.category_id = cat.id + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_id) cf ON cf.community_id = c.id; -create view community_view as -select +CREATE VIEW community_view AS +SELECT cv.*, - us.user as user_id, - us.is_subbed::bool as subscribed -from community_aggregates_view cv -cross join lateral ( - select - u.id as user, - coalesce(cf.community_id, 0) as is_subbed - from user_ u - left join community_follower cf on u.id = cf.user_id and cf.community_id = cv.id -) as us - -union all - -select + us.user AS user_id, + us.is_subbed::bool AS subscribed +FROM + community_aggregates_view cv + CROSS JOIN LATERAL ( + SELECT + u.id AS user, + coalesce(cf.community_id, 0) AS is_subbed + FROM + user_ u + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = cv.id) AS us +UNION ALL +SELECT cv.*, - null as user_id, - null as subscribed -from community_aggregates_view cv; + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_view cv; -create view community_moderator_view as -select +CREATE VIEW community_moderator_view AS +SELECT cm.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.preferred_username as user_preferred_username, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name, - c.icon as community_icon -from community_moderator cm -left join user_ u on cm.user_id = u.id -left join community c on cm.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.preferred_username AS user_preferred_username, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name, + c.icon AS community_icon +FROM + community_moderator cm + LEFT JOIN user_ u ON cm.user_id = u.id + LEFT JOIN community c ON cm.community_id = c.id; -create view community_follower_view as -select +CREATE VIEW community_follower_view AS +SELECT cf.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.preferred_username as user_preferred_username, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name, - c.icon as community_icon -from community_follower cf -left join user_ u on cf.user_id = u.id -left join community c on cf.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.preferred_username AS user_preferred_username, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name, + c.icon AS community_icon +FROM + community_follower cf + LEFT JOIN user_ u ON cf.user_id = u.id + LEFT JOIN community c ON cf.community_id = c.id; -create view community_user_ban_view as -select +CREATE VIEW community_user_ban_view AS +SELECT cb.*, - u.actor_id as user_actor_id, - u.local as user_local, - u.name as user_name, - u.preferred_username as user_preferred_username, - u.avatar as avatar, - c.actor_id as community_actor_id, - c.local as community_local, - c.name as community_name, - c.icon as community_icon -from community_user_ban cb -left join user_ u on cb.user_id = u.id -left join community c on cb.community_id = c.id; + u.actor_id AS user_actor_id, + u.local AS user_local, + u.name AS user_name, + u.preferred_username AS user_preferred_username, + u.avatar AS avatar, + c.actor_id AS community_actor_id, + c.local AS community_local, + c.name AS community_name, + c.icon AS community_icon +FROM + community_user_ban cb + LEFT JOIN user_ u ON cb.user_id = u.id + LEFT JOIN community c ON cb.community_id = c.id; -- The community fast table +CREATE TABLE community_aggregates_fast AS +SELECT + * +FROM + community_aggregates_view; -create table community_aggregates_fast as select * from community_aggregates_view; -alter table community_aggregates_fast add primary key (id); +ALTER TABLE community_aggregates_fast + ADD PRIMARY KEY (id); -create view community_fast_view as -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join ( - select - ca.* - from community_aggregates_fast ca -) ac - -union all - -select -caf.*, -null as user_id, -null as subscribed -from community_aggregates_fast caf; +CREATE VIEW community_fast_view AS +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + community_aggregates_fast ca) ac +UNION ALL +SELECT + caf.*, + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_fast caf; -- Comments, mentions, replies -drop view user_mention_view; -drop view reply_fast_view; -drop view comment_fast_view; -drop view comment_view; -drop view user_mention_fast_view; -drop table comment_aggregates_fast; -drop view comment_aggregates_view; +DROP VIEW user_mention_view; -create view comment_aggregates_view as -select - ct.*, - -- post details - p."name" as post_name, - p.community_id, - -- community details - c.actor_id as community_actor_id, - c."local" as community_local, - c."name" as community_name, - c.icon as community_icon, - -- creator details - u.banned as banned, - coalesce(cb.id, 0)::bool as banned_from_community, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.preferred_username as creator_preferred_username, - u.published as creator_published, - u.avatar as creator_avatar, - -- score details - coalesce(cl.total, 0) as score, - coalesce(cl.up, 0) as upvotes, - coalesce(cl.down, 0) as downvotes, - hot_rank(coalesce(cl.total, 1), p.published) as hot_rank, - hot_rank(coalesce(cl.total, 1), ct.published) as hot_rank_active -from comment ct -left join post p on ct.post_id = p.id -left join community c on p.community_id = c.id -left join user_ u on ct.creator_id = u.id -left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id -left join ( - select - l.comment_id as id, - sum(l.score) as total, - count(case when l.score = 1 then 1 else null end) as up, - count(case when l.score = -1 then 1 else null end) as down - from comment_like l - group by comment_id -) as cl on cl.id = ct.id; +DROP VIEW reply_fast_view; -create or replace view comment_view as ( -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_view cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +DROP VIEW comment_fast_view; -union all +DROP VIEW comment_view; -select +DROP VIEW user_mention_fast_view; + +DROP TABLE comment_aggregates_fast; + +DROP VIEW comment_aggregates_view; + +CREATE VIEW comment_aggregates_view AS +SELECT + ct.*, + -- post details + p."name" AS post_name, + p.community_id, + -- community details + c.actor_id AS community_actor_id, + c."local" AS community_local, + c."name" AS community_name, + c.icon AS community_icon, + -- creator details + u.banned AS banned, + coalesce(cb.id, 0)::bool AS banned_from_community, + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.published AS creator_published, + u.avatar AS creator_avatar, + -- score details + coalesce(cl.total, 0) AS score, + coalesce(cl.up, 0) AS upvotes, + coalesce(cl.down, 0) AS downvotes, + hot_rank (coalesce(cl.total, 1), p.published) AS hot_rank, + hot_rank (coalesce(cl.total, 1), ct.published) AS hot_rank_active +FROM + comment ct + LEFT JOIN post p ON ct.post_id = p.id + LEFT JOIN community c ON p.community_id = c.id + LEFT JOIN user_ u ON ct.creator_id = u.id + LEFT JOIN community_user_ban cb ON ct.creator_id = cb.user_id + AND p.id = ct.post_id + AND p.community_id = cb.community_id + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL + END) AS up, + count( + CASE WHEN l.score = - 1 THEN + 1 + ELSE + NULL + END) AS down + FROM + comment_like l + GROUP BY + comment_id) AS cl ON cl.id = ct.id; + +CREATE OR REPLACE VIEW comment_view AS ( + SELECT + cav.*, + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved + FROM + comment_aggregates_view cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_view cav -); + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_view cav); -create table comment_aggregates_fast as select * from comment_aggregates_view; -alter table comment_aggregates_fast add primary key (id); +CREATE TABLE comment_aggregates_fast AS +SELECT + * +FROM + comment_aggregates_view; -create view comment_fast_view as -select - cav.*, - us.user_id as user_id, - us.my_vote as my_vote, - us.is_subbed::bool as subscribed, - us.is_saved::bool as saved -from comment_aggregates_fast cav -cross join lateral ( - select - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - coalesce(cf.id, 0) as is_subbed, - coalesce(cs.id, 0) as is_saved - from user_ u - left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id - left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id - left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id -) as us +ALTER TABLE comment_aggregates_fast + ADD PRIMARY KEY (id); -union all - -select +CREATE VIEW comment_fast_view AS +SELECT cav.*, - null as user_id, - null as my_vote, - null as subscribed, - null as saved -from comment_aggregates_fast cav; + us.user_id AS user_id, + us.my_vote AS my_vote, + us.is_subbed::bool AS subscribed, + us.is_saved::bool AS saved +FROM + comment_aggregates_fast cav + CROSS JOIN LATERAL ( + SELECT + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + coalesce(cf.id, 0) AS is_subbed, + coalesce(cs.id, 0) AS is_saved + FROM + user_ u + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND cav.id = cl.comment_id + LEFT JOIN comment_saved cs ON u.id = cs.user_id + AND cs.comment_id = cav.id + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cav.community_id = cf.community_id) AS us +UNION ALL +SELECT + cav.*, + NULL AS user_id, + NULL AS my_vote, + NULL AS subscribed, + NULL AS saved +FROM + comment_aggregates_fast cav; -create view user_mention_view as -select +CREATE VIEW user_mention_view AS +SELECT c.id, - um.id as user_mention_id, + um.id AS user_mention_id, c.creator_id, c.creator_actor_id, c.creator_local, @@ -532,15 +644,30 @@ select c.my_vote, c.saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_mention um, comment_view c -where um.comment_id = c.id; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_mention um, + comment_view c +WHERE + um.comment_id = c.id; -create view user_mention_fast_view as -select +CREATE VIEW user_mention_fast_view AS +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -568,26 +695,45 @@ select ac.downvotes, ac.hot_rank, ac.hot_rank_active, - u.id as user_id, - coalesce(cl.score, 0) as my_vote, - (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + u.id AS user_id, + coalesce(cl.score, 0) AS my_vote, + ( + SELECT + cs.id::bool + FROM + comment_saved cs + WHERE + u.id = cs.user_id + AND cs.comment_id = ac.id) AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from user_ u -cross join ( - select - ca.* - from comment_aggregates_fast ca -) ac -left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id -left join user_mention um on um.comment_id = ac.id - -union all - -select + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + comment_aggregates_fast ca) ac + LEFT JOIN comment_like cl ON u.id = cl.user_id + AND ac.id = cl.comment_id + LEFT JOIN user_mention um ON um.comment_id = ac.id +UNION ALL +SELECT ac.id, - um.id as user_mention_id, + um.id AS user_mention_id, ac.creator_id, ac.creator_actor_id, ac.creator_local, @@ -615,134 +761,227 @@ select ac.downvotes, ac.hot_rank, ac.hot_rank_active, - null as user_id, - null as my_vote, - null as saved, + NULL AS user_id, + NULL AS my_vote, + NULL AS saved, um.recipient_id, - (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, - (select local from user_ u where u.id = um.recipient_id) as recipient_local -from comment_aggregates_fast ac -left join user_mention um on um.comment_id = ac.id -; + ( + SELECT + actor_id + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_actor_id, + ( + SELECT + local + FROM + user_ u + WHERE + u.id = um.recipient_id) AS recipient_local +FROM + comment_aggregates_fast ac + LEFT JOIN user_mention um ON um.comment_id = ac.id; -- Do the reply_view referencing the comment_fast_view -create view reply_fast_view as -with closereply as ( - select - c2.id, - c2.creator_id as sender_id, - c.creator_id as recipient_id - from comment c - inner join comment c2 on c.id = c2.parent_id - where c2.creator_id != c.creator_id - -- Do union where post is null - union - select - c.id, - c.creator_id as sender_id, - p.creator_id as recipient_id - from comment c, post p - where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +CREATE VIEW reply_fast_view AS +with closereply AS ( + SELECT + c2.id, + c2.creator_id AS sender_id, + c.creator_id AS recipient_id + FROM + comment c + INNER JOIN comment c2 ON c.id = c2.parent_id + WHERE + c2.creator_id != c.creator_id + -- Do union where post is null + UNION + SELECT + c.id, + c.creator_id AS sender_id, + p.creator_id AS recipient_id + FROM + comment c, + post p + WHERE + c.post_id = p.id + AND c.parent_id IS NULL + AND c.creator_id != p.creator_id ) -select cv.*, -closereply.recipient_id -from comment_fast_view cv, closereply -where closereply.id = cv.id -; +SELECT + cv.*, + closereply.recipient_id +FROM + comment_fast_view cv, + closereply +WHERE + closereply.id = cv.id; -- Adding hot rank active to the triggers -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank, + hot_rank_active = pav.hot_rank_active + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id; + -- Update the comment hot_ranks as of last week + UPDATE + comment_aggregates_fast AS caf + SET + hot_rank = cav.hot_rank, + hot_rank_active = cav.hot_rank_active + FROM + comment_aggregates_view AS cav + WHERE + caf.id = cav.id + AND (cav.published > ('now'::timestamp - '1 week'::interval)); + -- Update the post ranks + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank, + hot_rank_active = pav.hot_rank_active + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + -- Force the hot rank active as zero on 2 day-older posts (necro-bump) + UPDATE + post_aggregates_fast AS paf + SET + hot_rank_active = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '2 days'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set - hot_rank = pav.hot_rank, - hot_rank_active = pav.hot_rank_active - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id; - - -- Update the comment hot_ranks as of last week - update comment_aggregates_fast as caf - set - hot_rank = cav.hot_rank, - hot_rank_active = cav.hot_rank_active - from comment_aggregates_view as cav - where caf.id = cav.id and (cav.published > ('now'::timestamp - '1 week'::interval)); - - -- Update the post ranks - update post_aggregates_fast as paf - set - hot_rank = pav.hot_rank, - hot_rank_active = pav.hot_rank_active - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - - -- Force the hot rank active as zero on 2 day-older posts (necro-bump) - update post_aggregates_fast as paf - set hot_rank_active = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '2 days'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; diff --git a/migrations/2020-08-06-205355_update_community_post_count/down.sql b/migrations/2020-08-06-205355_update_community_post_count/down.sql index 53b016c88..984f407bc 100644 --- a/migrations/2020-08-06-205355_update_community_post_count/down.sql +++ b/migrations/2020-08-06-205355_update_community_post_count/down.sql @@ -1,11 +1,14 @@ -- Drop first -drop view community_view; -drop view community_aggregates_view; -drop view community_fast_view; -drop table community_aggregates_fast; +DROP VIEW community_view; -create view community_aggregates_view as -select +DROP VIEW community_aggregates_view; + +DROP VIEW community_fast_view; + +DROP TABLE community_aggregates_fast; + +CREATE VIEW community_aggregates_view AS +SELECT c.id, c.name, c.title, @@ -22,79 +25,96 @@ select c.actor_id, c.local, c.last_refreshed_at, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.preferred_username as creator_preferred_username, - u.avatar as creator_avatar, - cat.name as category_name, - coalesce(cf.subs, 0) as number_of_subscribers, - coalesce(cd.posts, 0) as number_of_posts, - coalesce(cd.comments, 0) as number_of_comments, - hot_rank(cf.subs, c.published) as hot_rank -from community c -left join user_ u on c.creator_id = u.id -left join category cat on c.category_id = cat.id -left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - join comment ct on p.id = ct.post_id - group by p.community_id -) cd on cd.community_id = c.id -left join ( - select - community_id, - count(*) as subs - from community_follower - group by community_id -) cf on cf.community_id = c.id; + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.avatar AS creator_avatar, + cat.name AS category_name, + coalesce(cf.subs, 0) AS number_of_subscribers, + coalesce(cd.posts, 0) AS number_of_posts, + coalesce(cd.comments, 0) AS number_of_comments, + hot_rank (cf.subs, c.published) AS hot_rank +FROM + community c + LEFT JOIN user_ u ON c.creator_id = u.id + LEFT JOIN category cat ON c.category_id = cat.id + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_id) cf ON cf.community_id = c.id; -create view community_view as -select +CREATE VIEW community_view AS +SELECT cv.*, - us.user as user_id, - us.is_subbed::bool as subscribed -from community_aggregates_view cv -cross join lateral ( - select - u.id as user, - coalesce(cf.community_id, 0) as is_subbed - from user_ u - left join community_follower cf on u.id = cf.user_id and cf.community_id = cv.id -) as us - -union all - -select + us.user AS user_id, + us.is_subbed::bool AS subscribed +FROM + community_aggregates_view cv + CROSS JOIN LATERAL ( + SELECT + u.id AS user, + coalesce(cf.community_id, 0) AS is_subbed + FROM + user_ u + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = cv.id) AS us +UNION ALL +SELECT cv.*, - null as user_id, - null as subscribed -from community_aggregates_view cv; + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_view cv; -- The community fast table +CREATE TABLE community_aggregates_fast AS +SELECT + * +FROM + community_aggregates_view; -create table community_aggregates_fast as select * from community_aggregates_view; -alter table community_aggregates_fast add primary key (id); +ALTER TABLE community_aggregates_fast + ADD PRIMARY KEY (id); -create view community_fast_view as -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join ( - select - ca.* - from community_aggregates_fast ca -) ac +CREATE VIEW community_fast_view AS +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + community_aggregates_fast ca) ac +UNION ALL +SELECT + caf.*, + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_fast caf; -union all - -select -caf.*, -null as user_id, -null as subscribed -from community_aggregates_fast caf; \ No newline at end of file diff --git a/migrations/2020-08-06-205355_update_community_post_count/up.sql b/migrations/2020-08-06-205355_update_community_post_count/up.sql index de5d447d1..8258f5d4c 100644 --- a/migrations/2020-08-06-205355_update_community_post_count/up.sql +++ b/migrations/2020-08-06-205355_update_community_post_count/up.sql @@ -1,11 +1,14 @@ -- Drop first -drop view community_view; -drop view community_aggregates_view; -drop view community_fast_view; -drop table community_aggregates_fast; +DROP VIEW community_view; -create view community_aggregates_view as -select +DROP VIEW community_aggregates_view; + +DROP VIEW community_fast_view; + +DROP TABLE community_aggregates_fast; + +CREATE VIEW community_aggregates_view AS +SELECT c.id, c.name, c.title, @@ -22,79 +25,96 @@ select c.actor_id, c.local, c.last_refreshed_at, - u.actor_id as creator_actor_id, - u.local as creator_local, - u.name as creator_name, - u.preferred_username as creator_preferred_username, - u.avatar as creator_avatar, - cat.name as category_name, - coalesce(cf.subs, 0) as number_of_subscribers, - coalesce(cd.posts, 0) as number_of_posts, - coalesce(cd.comments, 0) as number_of_comments, - hot_rank(cf.subs, c.published) as hot_rank -from community c -left join user_ u on c.creator_id = u.id -left join category cat on c.category_id = cat.id -left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - left join comment ct on p.id = ct.post_id - group by p.community_id -) cd on cd.community_id = c.id -left join ( - select - community_id, - count(*) as subs - from community_follower - group by community_id -) cf on cf.community_id = c.id; + u.actor_id AS creator_actor_id, + u.local AS creator_local, + u.name AS creator_name, + u.preferred_username AS creator_preferred_username, + u.avatar AS creator_avatar, + cat.name AS category_name, + coalesce(cf.subs, 0) AS number_of_subscribers, + coalesce(cd.posts, 0) AS number_of_posts, + coalesce(cd.comments, 0) AS number_of_comments, + hot_rank (cf.subs, c.published) AS hot_rank +FROM + community c + LEFT JOIN user_ u ON c.creator_id = u.id + LEFT JOIN category cat ON c.category_id = cat.id + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + LEFT JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_id) cf ON cf.community_id = c.id; -create view community_view as -select +CREATE VIEW community_view AS +SELECT cv.*, - us.user as user_id, - us.is_subbed::bool as subscribed -from community_aggregates_view cv -cross join lateral ( - select - u.id as user, - coalesce(cf.community_id, 0) as is_subbed - from user_ u - left join community_follower cf on u.id = cf.user_id and cf.community_id = cv.id -) as us - -union all - -select + us.user AS user_id, + us.is_subbed::bool AS subscribed +FROM + community_aggregates_view cv + CROSS JOIN LATERAL ( + SELECT + u.id AS user, + coalesce(cf.community_id, 0) AS is_subbed + FROM + user_ u + LEFT JOIN community_follower cf ON u.id = cf.user_id + AND cf.community_id = cv.id) AS us +UNION ALL +SELECT cv.*, - null as user_id, - null as subscribed -from community_aggregates_view cv; + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_view cv; -- The community fast table +CREATE TABLE community_aggregates_fast AS +SELECT + * +FROM + community_aggregates_view; -create table community_aggregates_fast as select * from community_aggregates_view; -alter table community_aggregates_fast add primary key (id); +ALTER TABLE community_aggregates_fast + ADD PRIMARY KEY (id); -create view community_fast_view as -select -ac.*, -u.id as user_id, -(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed -from user_ u -cross join ( - select - ca.* - from community_aggregates_fast ca -) ac +CREATE VIEW community_fast_view AS +SELECT + ac.*, + u.id AS user_id, + ( + SELECT + cf.id::boolean + FROM + community_follower cf + WHERE + u.id = cf.user_id + AND ac.id = cf.community_id) AS subscribed +FROM + user_ u + CROSS JOIN ( + SELECT + ca.* + FROM + community_aggregates_fast ca) ac +UNION ALL +SELECT + caf.*, + NULL AS user_id, + NULL AS subscribed +FROM + community_aggregates_fast caf; -union all - -select -caf.*, -null as user_id, -null as subscribed -from community_aggregates_fast caf; \ No newline at end of file diff --git a/migrations/2020-08-25-132005_add_unique_ap_ids/down.sql b/migrations/2020-08-25-132005_add_unique_ap_ids/down.sql index 2b43b59c3..1fce04baf 100644 --- a/migrations/2020-08-25-132005_add_unique_ap_ids/down.sql +++ b/migrations/2020-08-25-132005_add_unique_ap_ids/down.sql @@ -1,27 +1,55 @@ -- Drop the uniques -alter table private_message drop constraint idx_private_message_ap_id; -alter table post drop constraint idx_post_ap_id; -alter table comment drop constraint idx_comment_ap_id; -alter table user_ drop constraint idx_user_actor_id; -alter table community drop constraint idx_community_actor_id; +ALTER TABLE private_message + DROP CONSTRAINT idx_private_message_ap_id; -alter table private_message alter column ap_id set not null; -alter table private_message alter column ap_id set default 'http://fake.com'; +ALTER TABLE post + DROP CONSTRAINT idx_post_ap_id; -alter table post alter column ap_id set not null; -alter table post alter column ap_id set default 'http://fake.com'; +ALTER TABLE comment + DROP CONSTRAINT idx_comment_ap_id; -alter table comment alter column ap_id set not null; -alter table comment alter column ap_id set default 'http://fake.com'; +ALTER TABLE user_ + DROP CONSTRAINT idx_user_actor_id; -update private_message -set ap_id = 'http://fake.com' -where ap_id like 'changeme_%'; +ALTER TABLE community + DROP CONSTRAINT idx_community_actor_id; -update post -set ap_id = 'http://fake.com' -where ap_id like 'changeme_%'; +ALTER TABLE private_message + ALTER COLUMN ap_id SET NOT NULL; + +ALTER TABLE private_message + ALTER COLUMN ap_id SET DEFAULT 'http://fake.com'; + +ALTER TABLE post + ALTER COLUMN ap_id SET NOT NULL; + +ALTER TABLE post + ALTER COLUMN ap_id SET DEFAULT 'http://fake.com'; + +ALTER TABLE comment + ALTER COLUMN ap_id SET NOT NULL; + +ALTER TABLE comment + ALTER COLUMN ap_id SET DEFAULT 'http://fake.com'; + +UPDATE + private_message +SET + ap_id = 'http://fake.com' +WHERE + ap_id LIKE 'changeme_%'; + +UPDATE + post +SET + ap_id = 'http://fake.com' +WHERE + ap_id LIKE 'changeme_%'; + +UPDATE + comment +SET + ap_id = 'http://fake.com' +WHERE + ap_id LIKE 'changeme_%'; -update comment -set ap_id = 'http://fake.com' -where ap_id like 'changeme_%'; diff --git a/migrations/2020-08-25-132005_add_unique_ap_ids/up.sql b/migrations/2020-08-25-132005_add_unique_ap_ids/up.sql index 75e81eef2..22c275bec 100644 --- a/migrations/2020-08-25-132005_add_unique_ap_ids/up.sql +++ b/migrations/2020-08-25-132005_add_unique_ap_ids/up.sql @@ -1,56 +1,101 @@ -- Add unique ap_id for private_message, comment, and post - -- Need to delete the possible dupes for ones that don't start with the fake one -delete from private_message a using ( - select min(id) as id, ap_id - from private_message - group by ap_id having count(*) > 1 -) b -where a.ap_id = b.ap_id -and a.id <> b.id; +DELETE FROM private_message a USING ( + SELECT + min(id) AS id, + ap_id + FROM + private_message + GROUP BY + ap_id + HAVING + count(*) > 1) b +WHERE + a.ap_id = b.ap_id + AND a.id <> b.id; -delete from post a using ( - select min(id) as id, ap_id - from post - group by ap_id having count(*) > 1 -) b -where a.ap_id = b.ap_id -and a.id <> b.id; +DELETE FROM post a USING ( + SELECT + min(id) AS id, + ap_id + FROM + post + GROUP BY + ap_id + HAVING + count(*) > 1) b +WHERE + a.ap_id = b.ap_id + AND a.id <> b.id; -delete from comment a using ( - select min(id) as id, ap_id - from comment - group by ap_id having count(*) > 1 -) b -where a.ap_id = b.ap_id -and a.id <> b.id; +DELETE FROM comment a USING ( + SELECT + min(id) AS id, + ap_id + FROM + comment + GROUP BY + ap_id + HAVING + count(*) > 1) b +WHERE + a.ap_id = b.ap_id + AND a.id <> b.id; -- Replacing the current default on the columns, to the unique one -update private_message -set ap_id = generate_unique_changeme() -where ap_id = 'http://fake.com'; +UPDATE + private_message +SET + ap_id = generate_unique_changeme () +WHERE + ap_id = 'http://fake.com'; -update post -set ap_id = generate_unique_changeme() -where ap_id = 'http://fake.com'; +UPDATE + post +SET + ap_id = generate_unique_changeme () +WHERE + ap_id = 'http://fake.com'; -update comment -set ap_id = generate_unique_changeme() -where ap_id = 'http://fake.com'; +UPDATE + comment +SET + ap_id = generate_unique_changeme () +WHERE + ap_id = 'http://fake.com'; -- Add the unique indexes -alter table private_message alter column ap_id set not null; -alter table private_message alter column ap_id set default generate_unique_changeme(); +ALTER TABLE private_message + ALTER COLUMN ap_id SET NOT NULL; -alter table post alter column ap_id set not null; -alter table post alter column ap_id set default generate_unique_changeme(); +ALTER TABLE private_message + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); -alter table comment alter column ap_id set not null; -alter table comment alter column ap_id set default generate_unique_changeme(); +ALTER TABLE post + ALTER COLUMN ap_id SET NOT NULL; + +ALTER TABLE post + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); + +ALTER TABLE comment + ALTER COLUMN ap_id SET NOT NULL; + +ALTER TABLE comment + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); -- Add the uniques, for user_ and community too -alter table private_message add constraint idx_private_message_ap_id unique (ap_id); -alter table post add constraint idx_post_ap_id unique (ap_id); -alter table comment add constraint idx_comment_ap_id unique (ap_id); -alter table user_ add constraint idx_user_actor_id unique (actor_id); -alter table community add constraint idx_community_actor_id unique (actor_id); +ALTER TABLE private_message + ADD CONSTRAINT idx_private_message_ap_id UNIQUE (ap_id); + +ALTER TABLE post + ADD CONSTRAINT idx_post_ap_id UNIQUE (ap_id); + +ALTER TABLE comment + ADD CONSTRAINT idx_comment_ap_id UNIQUE (ap_id); + +ALTER TABLE user_ + ADD CONSTRAINT idx_user_actor_id UNIQUE (actor_id); + +ALTER TABLE community + ADD CONSTRAINT idx_community_actor_id UNIQUE (actor_id); + diff --git a/migrations/2020-09-07-231141_add_migration_utils/down.sql b/migrations/2020-09-07-231141_add_migration_utils/down.sql index 80dc308ac..bebe2856e 100644 --- a/migrations/2020-09-07-231141_add_migration_utils/down.sql +++ b/migrations/2020-09-07-231141_add_migration_utils/down.sql @@ -1 +1,2 @@ -drop schema utils cascade; \ No newline at end of file +DROP SCHEMA utils CASCADE; + diff --git a/migrations/2020-09-07-231141_add_migration_utils/up.sql b/migrations/2020-09-07-231141_add_migration_utils/up.sql index 8f9552ea9..7e2f794fa 100644 --- a/migrations/2020-09-07-231141_add_migration_utils/up.sql +++ b/migrations/2020-09-07-231141_add_migration_utils/up.sql @@ -1,89 +1,127 @@ -create schema utils; +CREATE SCHEMA utils; -create table utils.deps_saved_ddl -( - id serial NOT NULL, - view_schema character varying(255), - view_name character varying(255), - ddl_to_run text, - CONSTRAINT deps_saved_ddl_pkey PRIMARY KEY (id) +CREATE TABLE utils.deps_saved_ddl ( + id serial NOT NULL, + view_schema character varying(255), + view_name character varying(255), + ddl_to_run text, + CONSTRAINT deps_saved_ddl_pkey PRIMARY KEY (id) ); -create or replace function utils.save_and_drop_views(p_view_schema name, p_view_name name) +CREATE OR REPLACE FUNCTION utils.save_and_drop_views (p_view_schema name, p_view_name name) RETURNS void LANGUAGE plpgsql COST 100 -AS $BODY$ - -declare - v_curr record; -begin -for v_curr in -( - select obj_schema, obj_name, obj_type from - ( - with recursive recursive_deps(obj_schema, obj_name, obj_type, depth) as - ( - select p_view_schema::name, p_view_name, null::varchar, 0 - union - select dep_schema::varchar, dep_name::varchar, dep_type::varchar, recursive_deps.depth + 1 from - ( - select ref_nsp.nspname ref_schema, ref_cl.relname ref_name, - rwr_cl.relkind dep_type, - rwr_nsp.nspname dep_schema, - rwr_cl.relname dep_name - from pg_depend dep - join pg_class ref_cl on dep.refobjid = ref_cl.oid - join pg_namespace ref_nsp on ref_cl.relnamespace = ref_nsp.oid - join pg_rewrite rwr on dep.objid = rwr.oid - join pg_class rwr_cl on rwr.ev_class = rwr_cl.oid - join pg_namespace rwr_nsp on rwr_cl.relnamespace = rwr_nsp.oid - where dep.deptype = 'n' - and dep.classid = 'pg_rewrite'::regclass - ) deps - join recursive_deps on deps.ref_schema = recursive_deps.obj_schema and deps.ref_name = recursive_deps.obj_name - where (deps.ref_schema != deps.dep_schema or deps.ref_name != deps.dep_name) - ) - select obj_schema, obj_name, obj_type, depth - from recursive_deps - where depth > 0 - ) t - group by obj_schema, obj_name, obj_type - order by max(depth) desc -) loop - if v_curr.obj_type = 'v' then - insert into utils.deps_saved_ddl(view_schema, view_name, ddl_to_run) - select p_view_schema, p_view_name, 'CREATE VIEW ' || v_curr.obj_schema || '.' || v_curr.obj_name || ' AS ' || view_definition - from information_schema.views - where table_schema = v_curr.obj_schema and table_name = v_curr.obj_name; - - execute 'DROP VIEW' || ' ' || v_curr.obj_schema || '.' || v_curr.obj_name; - end if; -end loop; -end; + AS $BODY$ +DECLARE + v_curr record; +BEGIN + FOR v_curr IN ( + SELECT + obj_schema, + obj_name, + obj_type + FROM ( WITH RECURSIVE recursive_deps ( + obj_schema, + obj_name, + obj_type, + depth +) AS ( + SELECT + p_view_schema::name, + p_view_name, + NULL::varchar, + 0 + UNION + SELECT + dep_schema::varchar, + dep_name::varchar, + dep_type::varchar, + recursive_deps.depth + 1 + FROM ( + SELECT + ref_nsp.nspname ref_schema, + ref_cl.relname ref_name, + rwr_cl.relkind dep_type, + rwr_nsp.nspname dep_schema, + rwr_cl.relname dep_name + FROM + pg_depend dep + JOIN pg_class ref_cl ON dep.refobjid = ref_cl.oid + JOIN pg_namespace ref_nsp ON ref_cl.relnamespace = ref_nsp.oid + JOIN pg_rewrite rwr ON dep.objid = rwr.oid + JOIN pg_class rwr_cl ON rwr.ev_class = rwr_cl.oid + JOIN pg_namespace rwr_nsp ON rwr_cl.relnamespace = rwr_nsp.oid + WHERE + dep.deptype = 'n' + AND dep.classid = 'pg_rewrite'::regclass) deps + JOIN recursive_deps ON deps.ref_schema = recursive_deps.obj_schema + AND deps.ref_name = recursive_deps.obj_name + WHERE (deps.ref_schema != deps.dep_schema + OR deps.ref_name != deps.dep_name)) + SELECT + obj_schema, + obj_name, + obj_type, + depth + FROM + recursive_deps + WHERE + depth > 0) t + GROUP BY + obj_schema, + obj_name, + obj_type + ORDER BY + max(depth) DESC) + LOOP + IF v_curr.obj_type = 'v' THEN + INSERT INTO utils.deps_saved_ddl (view_schema, view_name, ddl_to_run) + SELECT + p_view_schema, + p_view_name, + 'CREATE VIEW ' || v_curr.obj_schema || '.' || v_curr.obj_name || ' AS ' || view_definition + FROM + information_schema.views + WHERE + table_schema = v_curr.obj_schema + AND table_name = v_curr.obj_name; + EXECUTE 'DROP VIEW' || ' ' || v_curr.obj_schema || '.' || v_curr.obj_name; + END IF; + END LOOP; +END; +$BODY$; + +CREATE OR REPLACE FUNCTION utils.restore_views (p_view_schema character varying, p_view_name character varying) + RETURNS void + LANGUAGE plpgsql + COST 100 + AS $BODY$ +DECLARE + v_curr record; +BEGIN + FOR v_curr IN ( + SELECT + ddl_to_run, + id + FROM + utils.deps_saved_ddl + WHERE + view_schema = p_view_schema + AND view_name = p_view_name + ORDER BY + id DESC) + LOOP + BEGIN + EXECUTE v_curr.ddl_to_run; + DELETE FROM utils.deps_saved_ddl + WHERE id = v_curr.id; + EXCEPTION + WHEN OTHERS THEN + -- keep looping, but please check for errors or remove left overs to handle manually + END; + END LOOP; +END; + $BODY$; -create or replace function utils.restore_views(p_view_schema character varying, p_view_name character varying) - RETURNS void - LANGUAGE plpgsql - COST 100 -AS $BODY$ -declare - v_curr record; -begin -for v_curr in -( - select ddl_to_run, id - from utils.deps_saved_ddl - where view_schema = p_view_schema and view_name = p_view_name - order by id desc -) loop -begin - execute v_curr.ddl_to_run; - delete from utils.deps_saved_ddl where id = v_curr.id; - EXCEPTION WHEN OTHERS THEN - -- keep looping, but please check for errors or remove left overs to handle manually - end; -end loop; -end; -$BODY$; \ No newline at end of file diff --git a/migrations/2020-10-07-234221_fix_fast_triggers/down.sql b/migrations/2020-10-07-234221_fix_fast_triggers/down.sql index 6b44e8a40..5a905564a 100644 --- a/migrations/2020-10-07-234221_fix_fast_triggers/down.sql +++ b/migrations/2020-10-07-234221_fix_fast_triggers/down.sql @@ -1,128 +1,245 @@ -create or replace function refresh_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from community_aggregates_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from community_aggregates_fast where id = OLD.id; - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id; +CREATE OR REPLACE FUNCTION refresh_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to owner changes + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update post view due to community changes + DELETE FROM post_aggregates_fast + WHERE community_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + community_id = NEW.id; + -- TODO make sure this shows up in the users page ? + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; - -- Update user view due to owner changes - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update post view due to community changes - delete from post_aggregates_fast where community_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where community_id = NEW.id; +CREATE OR REPLACE FUNCTION refresh_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id; + -- Refresh post_fast, cause of user info changes + DELETE FROM post_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + creator_id = NEW.id; + DELETE FROM comment_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + creator_id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; - -- TODO make sure this shows up in the users page ? - ELSIF (TG_OP = 'INSERT') THEN - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id; - END IF; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; - return null; -end $$; - -create or replace function refresh_user() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from user_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from user_fast where id = OLD.id; - insert into user_fast select * from user_view where id = NEW.id; - - -- Refresh post_fast, cause of user info changes - delete from post_aggregates_fast where creator_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where creator_id = NEW.id; - - delete from comment_aggregates_fast where creator_id = NEW.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where creator_id = NEW.id; - - ELSIF (TG_OP = 'INSERT') THEN - insert into user_fast select * from user_view where id = NEW.id; - END IF; - - return null; -end $$; - -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set hot_rank = pav.hot_rank - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id; - - -- Force the hot rank as zero on week-older posts - update post_aggregates_fast as paf - set hot_rank = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '1 week'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id; + -- Force the hot rank as zero on week-older posts + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '1 week'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; diff --git a/migrations/2020-10-07-234221_fix_fast_triggers/up.sql b/migrations/2020-10-07-234221_fix_fast_triggers/up.sql index 39f774470..f94cbf1be 100644 --- a/migrations/2020-10-07-234221_fix_fast_triggers/up.sql +++ b/migrations/2020-10-07-234221_fix_fast_triggers/up.sql @@ -1,132 +1,267 @@ -- This adds on conflict do nothing triggers to all the insert_intos -- Github issue: https://github.com/LemmyNet/lemmy/issues/1179 +CREATE OR REPLACE FUNCTION refresh_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM community_aggregates_fast + WHERE id = OLD.id; + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + -- Update user view due to owner changes + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id + ON CONFLICT (id) + DO NOTHING; + -- Update post view due to community changes + DELETE FROM post_aggregates_fast + WHERE community_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + community_id = NEW.id + ON CONFLICT (id) + DO NOTHING; + -- TODO make sure this shows up in the users page ? + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates_fast + SELECT + * + FROM + community_aggregates_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; -create or replace function refresh_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from community_aggregates_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from community_aggregates_fast where id = OLD.id; - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id on conflict (id) do nothing; +CREATE OR REPLACE FUNCTION refresh_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM user_fast + WHERE id = OLD.id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + -- Refresh post_fast, cause of user info changes + DELETE FROM post_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + creator_id = NEW.id + ON CONFLICT (id) + DO NOTHING; + DELETE FROM comment_aggregates_fast + WHERE creator_id = NEW.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + creator_id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.id; + END IF; + RETURN NULL; +END +$$; - -- Update user view due to owner changes - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id on conflict (id) do nothing; - - -- Update post view due to community changes - delete from post_aggregates_fast where community_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where community_id = NEW.id on conflict (id) do nothing; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id + ON CONFLICT (id) + DO NOTHING; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; - -- TODO make sure this shows up in the users page ? - ELSIF (TG_OP = 'INSERT') THEN - insert into community_aggregates_fast select * from community_aggregates_view where id = NEW.id; - END IF; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id + ON CONFLICT (id) + DO NOTHING; + -- Force the hot rank as zero on week-older posts + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '1 week'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - return null; -end $$; - -create or replace function refresh_user() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from user_fast where id = OLD.id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from user_fast where id = OLD.id; - insert into user_fast select * from user_view where id = NEW.id on conflict(id) do nothing; - - -- Refresh post_fast, cause of user info changes - delete from post_aggregates_fast where creator_id = NEW.id; - insert into post_aggregates_fast select * from post_aggregates_view where creator_id = NEW.id on conflict (id) do nothing; - - delete from comment_aggregates_fast where creator_id = NEW.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where creator_id = NEW.id on conflict (id) do nothing; - - ELSIF (TG_OP = 'INSERT') THEN - insert into user_fast select * from user_view where id = NEW.id; - END IF; - - return null; -end $$; - -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id on conflict (id) do nothing; - - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id on conflict (id) do nothing; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set hot_rank = pav.hot_rank - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id on conflict (id) do nothing; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id on conflict (id) do nothing; - - -- Force the hot rank as zero on week-older posts - update post_aggregates_fast as paf - set hot_rank = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '1 week'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; diff --git a/migrations/2020-10-10-035723_fix_fast_triggers_2/down.sql b/migrations/2020-10-10-035723_fix_fast_triggers_2/down.sql index d05418f5c..291913cb0 100644 --- a/migrations/2020-10-10-035723_fix_fast_triggers_2/down.sql +++ b/migrations/2020-10-10-035723_fix_fast_triggers_2/down.sql @@ -1,79 +1,151 @@ -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id + ON CONFLICT (id) + DO NOTHING; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id on conflict (id) do nothing; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id + ON CONFLICT (id) + DO NOTHING; + -- Force the hot rank as zero on week-older posts + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '1 week'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id on conflict (id) do nothing; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set hot_rank = pav.hot_rank - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id on conflict (id) do nothing; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id on conflict (id) do nothing; - - -- Force the hot rank as zero on week-older posts - update post_aggregates_fast as paf - set hot_rank = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '1 week'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; diff --git a/migrations/2020-10-10-035723_fix_fast_triggers_2/up.sql b/migrations/2020-10-10-035723_fix_fast_triggers_2/up.sql index 64a5dccb4..44934412f 100644 --- a/migrations/2020-10-10-035723_fix_fast_triggers_2/up.sql +++ b/migrations/2020-10-10-035723_fix_fast_triggers_2/up.sql @@ -1,97 +1,175 @@ -- Forgot to add hot rank active to these two triggers +CREATE OR REPLACE FUNCTION refresh_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts - 1 + WHERE + id = OLD.community_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM post_aggregates_fast + WHERE id = OLD.id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.id; + -- Update that users number of posts, post score + DELETE FROM user_fast + WHERE id = NEW.creator_id; + INSERT INTO user_fast + SELECT + * + FROM + user_view + WHERE + id = NEW.creator_id + ON CONFLICT (id) + DO NOTHING; + -- Update community number of posts + UPDATE + community_aggregates_fast + SET + number_of_posts = number_of_posts + 1 + WHERE + id = NEW.community_id; + -- Update the hot rank on the post table + -- TODO this might not correctly update it, using a 1 week interval + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank, + hot_rank_active = pav.hot_rank_active + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + END IF; + RETURN NULL; +END +$$; -create or replace function refresh_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from post_aggregates_fast where id = OLD.id; +CREATE OR REPLACE FUNCTION refresh_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments - 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + DELETE FROM comment_aggregates_fast + WHERE id = OLD.id; + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id + ON CONFLICT (id) + DO NOTHING; + ELSIF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates_fast + SELECT + * + FROM + comment_aggregates_view + WHERE + id = NEW.id; + -- Update user view due to comment count + UPDATE + user_fast + SET + number_of_comments = number_of_comments + 1 + WHERE + id = NEW.creator_id; + -- Update post view due to comment count, new comment activity time, but only on new posts + -- TODO this could be done more efficiently + DELETE FROM post_aggregates_fast + WHERE id = NEW.post_id; + INSERT INTO post_aggregates_fast + SELECT + * + FROM + post_aggregates_view + WHERE + id = NEW.post_id + ON CONFLICT (id) + DO NOTHING; + -- Update the comment hot_ranks as of last week + UPDATE + comment_aggregates_fast AS caf + SET + hot_rank = cav.hot_rank, + hot_rank_active = cav.hot_rank_active + FROM + comment_aggregates_view AS cav + WHERE + caf.id = cav.id + AND (cav.published > ('now'::timestamp - '1 week'::interval)); + -- Update the post ranks + UPDATE + post_aggregates_fast AS paf + SET + hot_rank = pav.hot_rank, + hot_rank_active = pav.hot_rank_active + FROM + post_aggregates_view AS pav + WHERE + paf.id = pav.id + AND (pav.published > ('now'::timestamp - '1 week'::interval)); + -- Force the hot rank active as zero on 2 day-older posts (necro-bump) + UPDATE + post_aggregates_fast AS paf + SET + hot_rank_active = 0 + WHERE + paf.id = NEW.post_id + AND (paf.published < ('now'::timestamp - '2 days'::interval)); + -- Update community number of comments + UPDATE + community_aggregates_fast AS caf + SET + number_of_comments = number_of_comments + 1 + FROM + post AS p + WHERE + caf.id = p.community_id + AND p.id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts - 1 where id = OLD.community_id; - ELSIF (TG_OP = 'UPDATE') THEN - delete from post_aggregates_fast where id = OLD.id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id on conflict (id) do nothing; - ELSIF (TG_OP = 'INSERT') THEN - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.id; - - -- Update that users number of posts, post score - delete from user_fast where id = NEW.creator_id; - insert into user_fast select * from user_view where id = NEW.creator_id on conflict (id) do nothing; - - -- Update community number of posts - update community_aggregates_fast set number_of_posts = number_of_posts + 1 where id = NEW.community_id; - - -- Update the hot rank on the post table - -- TODO this might not correctly update it, using a 1 week interval - update post_aggregates_fast as paf - set - hot_rank = pav.hot_rank, - hot_rank_active = pav.hot_rank_active - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - END IF; - - return null; -end $$; - -create or replace function refresh_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - delete from comment_aggregates_fast where id = OLD.id; - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments - 1 - from post as p - where caf.id = p.community_id and p.id = OLD.post_id; - - ELSIF (TG_OP = 'UPDATE') THEN - delete from comment_aggregates_fast where id = OLD.id; - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id on conflict (id) do nothing; - ELSIF (TG_OP = 'INSERT') THEN - insert into comment_aggregates_fast select * from comment_aggregates_view where id = NEW.id; - - -- Update user view due to comment count - update user_fast - set number_of_comments = number_of_comments + 1 - where id = NEW.creator_id; - - -- Update post view due to comment count, new comment activity time, but only on new posts - -- TODO this could be done more efficiently - delete from post_aggregates_fast where id = NEW.post_id; - insert into post_aggregates_fast select * from post_aggregates_view where id = NEW.post_id on conflict (id) do nothing; - - -- Update the comment hot_ranks as of last week - update comment_aggregates_fast as caf - set - hot_rank = cav.hot_rank, - hot_rank_active = cav.hot_rank_active - from comment_aggregates_view as cav - where caf.id = cav.id and (cav.published > ('now'::timestamp - '1 week'::interval)); - - -- Update the post ranks - update post_aggregates_fast as paf - set - hot_rank = pav.hot_rank, - hot_rank_active = pav.hot_rank_active - from post_aggregates_view as pav - where paf.id = pav.id and (pav.published > ('now'::timestamp - '1 week'::interval)); - - -- Force the hot rank active as zero on 2 day-older posts (necro-bump) - update post_aggregates_fast as paf - set hot_rank_active = 0 - where paf.id = NEW.post_id and (paf.published < ('now'::timestamp - '2 days'::interval)); - - -- Update community number of comments - update community_aggregates_fast as caf - set number_of_comments = number_of_comments + 1 - from post as p - where caf.id = p.community_id and p.id = NEW.post_id; - - END IF; - - return null; -end $$; diff --git a/migrations/2020-10-13-212240_create_report_tables/down.sql b/migrations/2020-10-13-212240_create_report_tables/down.sql index e1c39faaf..9dfdbd48e 100644 --- a/migrations/2020-10-13-212240_create_report_tables/down.sql +++ b/migrations/2020-10-13-212240_create_report_tables/down.sql @@ -1,4 +1,8 @@ -drop view comment_report_view; -drop view post_report_view; -drop table comment_report; -drop table post_report; +DROP VIEW comment_report_view; + +DROP VIEW post_report_view; + +DROP TABLE comment_report; + +DROP TABLE post_report; + diff --git a/migrations/2020-10-13-212240_create_report_tables/up.sql b/migrations/2020-10-13-212240_create_report_tables/up.sql index e9dce1adb..9aafa3a70 100644 --- a/migrations/2020-10-13-212240_create_report_tables/up.sql +++ b/migrations/2020-10-13-212240_create_report_tables/up.sql @@ -1,89 +1,94 @@ -create table comment_report ( - id serial primary key, - creator_id int references user_ on update cascade on delete cascade not null, -- user reporting comment - comment_id int references comment on update cascade on delete cascade not null, -- comment being reported - original_comment_text text not null, - reason text not null, - resolved bool not null default false, - resolver_id int references user_ on update cascade on delete cascade, -- user resolving report - published timestamp not null default now(), - updated timestamp null, - unique(comment_id, creator_id) -- users should only be able to report a comment once +CREATE TABLE comment_report ( + id serial PRIMARY KEY, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- user reporting comment + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- comment being reported + original_comment_text text NOT NULL, + reason text NOT NULL, + resolved bool NOT NULL DEFAULT FALSE, + resolver_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE, -- user resolving report + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL, + UNIQUE (comment_id, creator_id) -- users should only be able to report a comment once ); -create table post_report ( - id serial primary key, - creator_id int references user_ on update cascade on delete cascade not null, -- user reporting post - post_id int references post on update cascade on delete cascade not null, -- post being reported - original_post_name varchar(100) not null, - original_post_url text, - original_post_body text, - reason text not null, - resolved bool not null default false, - resolver_id int references user_ on update cascade on delete cascade, -- user resolving report - published timestamp not null default now(), - updated timestamp null, - unique(post_id, creator_id) -- users should only be able to report a post once +CREATE TABLE post_report ( + id serial PRIMARY KEY, + creator_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- user reporting post + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- post being reported + original_post_name varchar(100) NOT NULL, + original_post_url text, + original_post_body text, + reason text NOT NULL, + resolved bool NOT NULL DEFAULT FALSE, + resolver_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE, -- user resolving report + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL, + UNIQUE (post_id, creator_id) -- users should only be able to report a post once ); -create or replace view comment_report_view as -select cr.*, -c.post_id, -c.content as current_comment_text, -p.community_id, --- report creator details -f.actor_id as creator_actor_id, -f.name as creator_name, -f.preferred_username as creator_preferred_username, -f.avatar as creator_avatar, -f.local as creator_local, --- comment creator details -u.id as comment_creator_id, -u.actor_id as comment_creator_actor_id, -u.name as comment_creator_name, -u.preferred_username as comment_creator_preferred_username, -u.avatar as comment_creator_avatar, -u.local as comment_creator_local, --- resolver details -r.actor_id as resolver_actor_id, -r.name as resolver_name, -r.preferred_username as resolver_preferred_username, -r.avatar as resolver_avatar, -r.local as resolver_local -from comment_report cr -left join comment c on c.id = cr.comment_id -left join post p on p.id = c.post_id -left join user_ u on u.id = c.creator_id -left join user_ f on f.id = cr.creator_id -left join user_ r on r.id = cr.resolver_id; +CREATE OR REPLACE VIEW comment_report_view AS +SELECT + cr.*, + c.post_id, + c.content AS current_comment_text, + p.community_id, + -- report creator details + f.actor_id AS creator_actor_id, + f.name AS creator_name, + f.preferred_username AS creator_preferred_username, + f.avatar AS creator_avatar, + f.local AS creator_local, + -- comment creator details + u.id AS comment_creator_id, + u.actor_id AS comment_creator_actor_id, + u.name AS comment_creator_name, + u.preferred_username AS comment_creator_preferred_username, + u.avatar AS comment_creator_avatar, + u.local AS comment_creator_local, + -- resolver details + r.actor_id AS resolver_actor_id, + r.name AS resolver_name, + r.preferred_username AS resolver_preferred_username, + r.avatar AS resolver_avatar, + r.local AS resolver_local +FROM + comment_report cr + LEFT JOIN comment c ON c.id = cr.comment_id + LEFT JOIN post p ON p.id = c.post_id + LEFT JOIN user_ u ON u.id = c.creator_id + LEFT JOIN user_ f ON f.id = cr.creator_id + LEFT JOIN user_ r ON r.id = cr.resolver_id; + +CREATE OR REPLACE VIEW post_report_view AS +SELECT + pr.*, + p.name AS current_post_name, + p.url AS current_post_url, + p.body AS current_post_body, + p.community_id, + -- report creator details + f.actor_id AS creator_actor_id, + f.name AS creator_name, + f.preferred_username AS creator_preferred_username, + f.avatar AS creator_avatar, + f.local AS creator_local, + -- post creator details + u.id AS post_creator_id, + u.actor_id AS post_creator_actor_id, + u.name AS post_creator_name, + u.preferred_username AS post_creator_preferred_username, + u.avatar AS post_creator_avatar, + u.local AS post_creator_local, + -- resolver details + r.actor_id AS resolver_actor_id, + r.name AS resolver_name, + r.preferred_username AS resolver_preferred_username, + r.avatar AS resolver_avatar, + r.local AS resolver_local +FROM + post_report pr + LEFT JOIN post p ON p.id = pr.post_id + LEFT JOIN user_ u ON u.id = p.creator_id + LEFT JOIN user_ f ON f.id = pr.creator_id + LEFT JOIN user_ r ON r.id = pr.resolver_id; -create or replace view post_report_view as -select pr.*, -p.name as current_post_name, -p.url as current_post_url, -p.body as current_post_body, -p.community_id, --- report creator details -f.actor_id as creator_actor_id, -f.name as creator_name, -f.preferred_username as creator_preferred_username, -f.avatar as creator_avatar, -f.local as creator_local, --- post creator details -u.id as post_creator_id, -u.actor_id as post_creator_actor_id, -u.name as post_creator_name, -u.preferred_username as post_creator_preferred_username, -u.avatar as post_creator_avatar, -u.local as post_creator_local, --- resolver details -r.actor_id as resolver_actor_id, -r.name as resolver_name, -r.preferred_username as resolver_preferred_username, -r.avatar as resolver_avatar, -r.local as resolver_local -from post_report pr -left join post p on p.id = pr.post_id -left join user_ u on u.id = p.creator_id -left join user_ f on f.id = pr.creator_id -left join user_ r on r.id = pr.resolver_id; diff --git a/migrations/2020-10-23-115011_activity_ap_id_column/down.sql b/migrations/2020-10-23-115011_activity_ap_id_column/down.sql index 7978df72e..5abef5a7f 100644 --- a/migrations/2020-10-23-115011_activity_ap_id_column/down.sql +++ b/migrations/2020-10-23-115011_activity_ap_id_column/down.sql @@ -1 +1,3 @@ -ALTER TABLE activity DROP COLUMN ap_id; \ No newline at end of file +ALTER TABLE activity + DROP COLUMN ap_id; + diff --git a/migrations/2020-10-23-115011_activity_ap_id_column/up.sql b/migrations/2020-10-23-115011_activity_ap_id_column/up.sql index ab22a4c44..d0df8814a 100644 --- a/migrations/2020-10-23-115011_activity_ap_id_column/up.sql +++ b/migrations/2020-10-23-115011_activity_ap_id_column/up.sql @@ -1 +1,3 @@ -ALTER TABLE activity ADD COLUMN ap_id TEXT; \ No newline at end of file +ALTER TABLE activity + ADD COLUMN ap_id TEXT; + diff --git a/migrations/2020-11-05-152724_activity_remove_user_id/down.sql b/migrations/2020-11-05-152724_activity_remove_user_id/down.sql index bb093f1bb..580c93e0d 100644 --- a/migrations/2020-11-05-152724_activity_remove_user_id/down.sql +++ b/migrations/2020-11-05-152724_activity_remove_user_id/down.sql @@ -1,2 +1,6 @@ -ALTER TABLE activity ADD COLUMN user_id INTEGER; -ALTER TABLE activity DROP COLUMN sensitive; \ No newline at end of file +ALTER TABLE activity + ADD COLUMN user_id INTEGER; + +ALTER TABLE activity + DROP COLUMN sensitive; + diff --git a/migrations/2020-11-05-152724_activity_remove_user_id/up.sql b/migrations/2020-11-05-152724_activity_remove_user_id/up.sql index 22a1a2fae..66b33dd8b 100644 --- a/migrations/2020-11-05-152724_activity_remove_user_id/up.sql +++ b/migrations/2020-11-05-152724_activity_remove_user_id/up.sql @@ -1,2 +1,6 @@ -ALTER TABLE activity DROP COLUMN user_id; -ALTER TABLE activity ADD COLUMN sensitive BOOLEAN DEFAULT TRUE; \ No newline at end of file +ALTER TABLE activity + DROP COLUMN user_id; + +ALTER TABLE activity + ADD COLUMN sensitive BOOLEAN DEFAULT TRUE; + diff --git a/migrations/2020-11-10-150835_community_follower_pending/down.sql b/migrations/2020-11-10-150835_community_follower_pending/down.sql index 72cbeaa37..f61482f9d 100644 --- a/migrations/2020-11-10-150835_community_follower_pending/down.sql +++ b/migrations/2020-11-10-150835_community_follower_pending/down.sql @@ -1 +1,3 @@ -ALTER TABLE community_follower DROP COLUMN pending; \ No newline at end of file +ALTER TABLE community_follower + DROP COLUMN pending; + diff --git a/migrations/2020-11-10-150835_community_follower_pending/up.sql b/migrations/2020-11-10-150835_community_follower_pending/up.sql index 599bed624..163dc0523 100644 --- a/migrations/2020-11-10-150835_community_follower_pending/up.sql +++ b/migrations/2020-11-10-150835_community_follower_pending/up.sql @@ -1 +1,3 @@ -ALTER TABLE community_follower ADD COLUMN pending BOOLEAN DEFAULT FALSE; \ No newline at end of file +ALTER TABLE community_follower + ADD COLUMN pending BOOLEAN DEFAULT FALSE; + diff --git a/migrations/2020-11-26-134531_delete_user/down.sql b/migrations/2020-11-26-134531_delete_user/down.sql index 09b05878c..51a9ef6bc 100644 --- a/migrations/2020-11-26-134531_delete_user/down.sql +++ b/migrations/2020-11-26-134531_delete_user/down.sql @@ -1 +1,3 @@ -ALTER TABLE user_ DROP COLUMN deleted; +ALTER TABLE user_ + DROP COLUMN deleted; + diff --git a/migrations/2020-11-26-134531_delete_user/up.sql b/migrations/2020-11-26-134531_delete_user/up.sql index 1d752c573..7fc226f6a 100644 --- a/migrations/2020-11-26-134531_delete_user/up.sql +++ b/migrations/2020-11-26-134531_delete_user/up.sql @@ -1 +1,3 @@ -ALTER TABLE user_ ADD COLUMN deleted BOOLEAN DEFAULT FALSE NOT NULL; +ALTER TABLE user_ + ADD COLUMN deleted BOOLEAN DEFAULT FALSE NOT NULL; + diff --git a/migrations/2020-12-02-152437_create_site_aggregates/down.sql b/migrations/2020-12-02-152437_create_site_aggregates/down.sql index 914bdb8d8..6535f0da9 100644 --- a/migrations/2020-12-02-152437_create_site_aggregates/down.sql +++ b/migrations/2020-12-02-152437_create_site_aggregates/down.sql @@ -1,21 +1,23 @@ -- Site aggregates -drop table site_aggregates; -drop trigger site_aggregates_site on site; -drop trigger site_aggregates_user_insert on user_; -drop trigger site_aggregates_user_delete on user_; -drop trigger site_aggregates_post_insert on post; -drop trigger site_aggregates_post_delete on post; -drop trigger site_aggregates_comment_insert on comment; -drop trigger site_aggregates_comment_delete on comment; -drop trigger site_aggregates_community_insert on community; -drop trigger site_aggregates_community_delete on community; -drop function - site_aggregates_site, - site_aggregates_user_insert, - site_aggregates_user_delete, - site_aggregates_post_insert, - site_aggregates_post_delete, - site_aggregates_comment_insert, - site_aggregates_comment_delete, - site_aggregates_community_insert, - site_aggregates_community_delete; +DROP TABLE site_aggregates; + +DROP TRIGGER site_aggregates_site ON site; + +DROP TRIGGER site_aggregates_user_insert ON user_; + +DROP TRIGGER site_aggregates_user_delete ON user_; + +DROP TRIGGER site_aggregates_post_insert ON post; + +DROP TRIGGER site_aggregates_post_delete ON post; + +DROP TRIGGER site_aggregates_comment_insert ON comment; + +DROP TRIGGER site_aggregates_comment_delete ON comment; + +DROP TRIGGER site_aggregates_community_insert ON community; + +DROP TRIGGER site_aggregates_community_delete ON community; + +DROP FUNCTION site_aggregates_site, site_aggregates_user_insert, site_aggregates_user_delete, site_aggregates_post_insert, site_aggregates_post_delete, site_aggregates_comment_insert, site_aggregates_comment_delete, site_aggregates_community_insert, site_aggregates_community_delete; + diff --git a/migrations/2020-12-02-152437_create_site_aggregates/up.sql b/migrations/2020-12-02-152437_create_site_aggregates/up.sql index 679543d19..79b5a9f87 100644 --- a/migrations/2020-12-02-152437_create_site_aggregates/up.sql +++ b/migrations/2020-12-02-152437_create_site_aggregates/up.sql @@ -1,169 +1,240 @@ -- Add site aggregates -create table site_aggregates ( - id serial primary key, - site_id int references site on update cascade on delete cascade not null, - users bigint not null default 1, - posts bigint not null default 0, - comments bigint not null default 0, - communities bigint not null default 0 +CREATE TABLE site_aggregates ( + id serial PRIMARY KEY, + site_id int REFERENCES site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + users bigint NOT NULL DEFAULT 1, + posts bigint NOT NULL DEFAULT 0, + comments bigint NOT NULL DEFAULT 0, + communities bigint NOT NULL DEFAULT 0 ); -insert into site_aggregates (site_id, users, posts, comments, communities) - select id as site_id, - ( select coalesce(count(*), 0) from user_ where local = true) as users, - ( select coalesce(count(*), 0) from post where local = true) as posts, - ( select coalesce(count(*), 0) from comment where local = true) as comments, - ( select coalesce(count(*), 0) from community where local = true) as communities - from site; +INSERT INTO site_aggregates (site_id, users, posts, comments, communities) +SELECT + id AS site_id, + ( + SELECT + coalesce(count(*), 0) + FROM + user_ + WHERE + local = TRUE) AS users, + ( + SELECT + coalesce(count(*), 0) + FROM + post + WHERE + local = TRUE) AS posts, + ( + SELECT + coalesce(count(*), 0) + FROM + comment + WHERE + local = TRUE) AS comments, + ( + SELECT + coalesce(count(*), 0) + FROM + community + WHERE + local = TRUE) AS communities +FROM + site; -- initial site add -create function site_aggregates_site() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into site_aggregates (site_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from site_aggregates where site_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION site_aggregates_site () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO site_aggregates (site_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM site_aggregates + WHERE site_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger site_aggregates_site -after insert or delete on site -for each row -execute procedure site_aggregates_site(); +CREATE TRIGGER site_aggregates_site + AFTER INSERT OR DELETE ON site + FOR EACH ROW + EXECUTE PROCEDURE site_aggregates_site (); -- Add site aggregate triggers -- user -create function site_aggregates_user_insert() -returns trigger language plpgsql -as $$ -begin - update site_aggregates - set users = users + 1; - return null; -end $$; +CREATE FUNCTION site_aggregates_user_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + users = users + 1; + RETURN NULL; +END +$$; -create function site_aggregates_user_delete() -returns trigger language plpgsql -as $$ -begin - -- Join to site since the creator might not be there anymore - update site_aggregates sa - set users = users - 1 - from site s - where sa.site_id = s.id; - return null; -end $$; +CREATE FUNCTION site_aggregates_user_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- Join to site since the creator might not be there anymore + UPDATE + site_aggregates sa + SET + users = users - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create trigger site_aggregates_user_insert -after insert on user_ -for each row -when (NEW.local = true) -execute procedure site_aggregates_user_insert(); +CREATE TRIGGER site_aggregates_user_insert + AFTER INSERT ON user_ + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_user_insert (); -create trigger site_aggregates_user_delete -after delete on user_ -for each row -when (OLD.local = true) -execute procedure site_aggregates_user_delete(); +CREATE TRIGGER site_aggregates_user_delete + AFTER DELETE ON user_ + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_user_delete (); -- post -create function site_aggregates_post_insert() -returns trigger language plpgsql -as $$ -begin - update site_aggregates - set posts = posts + 1; - return null; -end $$; +CREATE FUNCTION site_aggregates_post_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + posts = posts + 1; + RETURN NULL; +END +$$; -create function site_aggregates_post_delete() -returns trigger language plpgsql -as $$ -begin - update site_aggregates sa - set posts = posts - 1 - from site s - where sa.site_id = s.id; - return null; -end $$; +CREATE FUNCTION site_aggregates_post_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + posts = posts - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create trigger site_aggregates_post_insert -after insert on post -for each row -when (NEW.local = true) -execute procedure site_aggregates_post_insert(); +CREATE TRIGGER site_aggregates_post_insert + AFTER INSERT ON post + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_insert (); -create trigger site_aggregates_post_delete -after delete on post -for each row -when (OLD.local = true) -execute procedure site_aggregates_post_delete(); +CREATE TRIGGER site_aggregates_post_delete + AFTER DELETE ON post + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_delete (); -- comment -create function site_aggregates_comment_insert() -returns trigger language plpgsql -as $$ -begin - update site_aggregates - set comments = comments + 1; - return null; -end $$; +CREATE FUNCTION site_aggregates_comment_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + comments = comments + 1; + RETURN NULL; +END +$$; -create function site_aggregates_comment_delete() -returns trigger language plpgsql -as $$ -begin - update site_aggregates sa - set comments = comments - 1 - from site s - where sa.site_id = s.id; - return null; -end $$; +CREATE FUNCTION site_aggregates_comment_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + comments = comments - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create trigger site_aggregates_comment_insert -after insert on comment -for each row -when (NEW.local = true) -execute procedure site_aggregates_comment_insert(); +CREATE TRIGGER site_aggregates_comment_insert + AFTER INSERT ON comment + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_insert (); -create trigger site_aggregates_comment_delete -after delete on comment -for each row -when (OLD.local = true) -execute procedure site_aggregates_comment_delete(); +CREATE TRIGGER site_aggregates_comment_delete + AFTER DELETE ON comment + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_delete (); -- community -create function site_aggregates_community_insert() -returns trigger language plpgsql -as $$ -begin - update site_aggregates - set communities = communities + 1; - return null; -end $$; +CREATE FUNCTION site_aggregates_community_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + communities = communities + 1; + RETURN NULL; +END +$$; -create function site_aggregates_community_delete() -returns trigger language plpgsql -as $$ -begin - update site_aggregates sa - set communities = communities - 1 - from site s - where sa.site_id = s.id; - return null; -end $$; +CREATE FUNCTION site_aggregates_community_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + communities = communities - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create trigger site_aggregates_community_insert -after insert on community -for each row -when (NEW.local = true) -execute procedure site_aggregates_community_insert(); +CREATE TRIGGER site_aggregates_community_insert + AFTER INSERT ON community + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_insert (); + +CREATE TRIGGER site_aggregates_community_delete + AFTER DELETE ON community + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_delete (); -create trigger site_aggregates_community_delete -after delete on community -for each row -when (OLD.local = true) -execute procedure site_aggregates_community_delete(); diff --git a/migrations/2020-12-03-035643_create_user_aggregates/down.sql b/migrations/2020-12-03-035643_create_user_aggregates/down.sql index a7b5e4737..756919d93 100644 --- a/migrations/2020-12-03-035643_create_user_aggregates/down.sql +++ b/migrations/2020-12-03-035643_create_user_aggregates/down.sql @@ -1,13 +1,15 @@ -- User aggregates -drop table user_aggregates; -drop trigger user_aggregates_user on user_; -drop trigger user_aggregates_post_count on post; -drop trigger user_aggregates_post_score on post_like; -drop trigger user_aggregates_comment_count on comment; -drop trigger user_aggregates_comment_score on comment_like; -drop function - user_aggregates_user, - user_aggregates_post_count, - user_aggregates_post_score, - user_aggregates_comment_count, - user_aggregates_comment_score; +DROP TABLE user_aggregates; + +DROP TRIGGER user_aggregates_user ON user_; + +DROP TRIGGER user_aggregates_post_count ON post; + +DROP TRIGGER user_aggregates_post_score ON post_like; + +DROP TRIGGER user_aggregates_comment_count ON comment; + +DROP TRIGGER user_aggregates_comment_score ON comment_like; + +DROP FUNCTION user_aggregates_user, user_aggregates_post_count, user_aggregates_post_score, user_aggregates_comment_count, user_aggregates_comment_score; + diff --git a/migrations/2020-12-03-035643_create_user_aggregates/up.sql b/migrations/2020-12-03-035643_create_user_aggregates/up.sql index 7b4c83af2..79218b90e 100644 --- a/migrations/2020-12-03-035643_create_user_aggregates/up.sql +++ b/migrations/2020-12-03-035643_create_user_aggregates/up.sql @@ -1,178 +1,236 @@ -- Add user aggregates -create table user_aggregates ( - id serial primary key, - user_id int references user_ on update cascade on delete cascade not null, - post_count bigint not null default 0, - post_score bigint not null default 0, - comment_count bigint not null default 0, - comment_score bigint not null default 0, - unique (user_id) +CREATE TABLE user_aggregates ( + id serial PRIMARY KEY, + user_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_count bigint NOT NULL DEFAULT 0, + post_score bigint NOT NULL DEFAULT 0, + comment_count bigint NOT NULL DEFAULT 0, + comment_score bigint NOT NULL DEFAULT 0, + UNIQUE (user_id) ); -insert into user_aggregates (user_id, post_count, post_score, comment_count, comment_score) - select u.id, - coalesce(pd.posts, 0), - coalesce(pd.score, 0), - coalesce(cd.comments, 0), - coalesce(cd.score, 0) - from user_ u - left join ( - select p.creator_id, - count(distinct p.id) as posts, - sum(pl.score) as score - from post p - left join post_like pl on p.id = pl.post_id - group by p.creator_id - ) pd on u.id = pd.creator_id - left join ( - select c.creator_id, - count(distinct c.id) as comments, - sum(cl.score) as score - from comment c - left join comment_like cl on c.id = cl.comment_id - group by c.creator_id - ) cd on u.id = cd.creator_id; - +INSERT INTO user_aggregates (user_id, post_count, post_score, comment_count, comment_score) +SELECT + u.id, + coalesce(pd.posts, 0), + coalesce(pd.score, 0), + coalesce(cd.comments, 0), + coalesce(cd.score, 0) +FROM + user_ u + LEFT JOIN ( + SELECT + p.creator_id, + count(DISTINCT p.id) AS posts, + sum(pl.score) AS score + FROM + post p + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + p.creator_id) pd ON u.id = pd.creator_id + LEFT JOIN ( + SELECT + c.creator_id, + count(DISTINCT c.id) AS comments, + sum(cl.score) AS score + FROM + comment c + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + c.creator_id) cd ON u.id = cd.creator_id; -- Add user aggregate triggers - -- initial user add -create function user_aggregates_user() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into user_aggregates (user_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from user_aggregates where user_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO user_aggregates (user_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM user_aggregates + WHERE user_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger user_aggregates_user -after insert or delete on user_ -for each row -execute procedure user_aggregates_user(); +CREATE TRIGGER user_aggregates_user + AFTER INSERT OR DELETE ON user_ + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_user (); -- post count -create function user_aggregates_post_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update user_aggregates - set post_count = post_count + 1 where user_id = NEW.creator_id; +CREATE FUNCTION user_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + user_aggregates + SET + post_count = post_count + 1 + WHERE + user_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates + SET + post_count = post_count - 1 + WHERE + user_id = OLD.creator_id; + -- If the post gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + user_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + user_ u + LEFT JOIN post p ON u.id = p.creator_id + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.user_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates - set post_count = post_count - 1 where user_id = OLD.creator_id; - - -- If the post gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update user_aggregates ua - set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from user_ u - left join post p on u.id = p.creator_id - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd - where ua.user_id = OLD.creator_id; - - END IF; - return null; -end $$; - -create trigger user_aggregates_post_count -after insert or delete on post -for each row -execute procedure user_aggregates_post_count(); +CREATE TRIGGER user_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_post_count (); -- post score -create function user_aggregates_post_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update user_aggregates ua - set post_score = post_score + NEW.score - from post p - where ua.user_id = p.creator_id and p.id = NEW.post_id; - - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates ua - set post_score = post_score - OLD.score - from post p - where ua.user_id = p.creator_id and p.id = OLD.post_id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_post_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + user_aggregates ua + SET + post_score = post_score + NEW.score + FROM + post p + WHERE + ua.user_id = p.creator_id + AND p.id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates ua + SET + post_score = post_score - OLD.score + FROM + post p + WHERE + ua.user_id = p.creator_id + AND p.id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -create trigger user_aggregates_post_score -after insert or delete on post_like -for each row -execute procedure user_aggregates_post_score(); +CREATE TRIGGER user_aggregates_post_score + AFTER INSERT OR DELETE ON post_like + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_post_score (); -- comment count -create function user_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update user_aggregates - set comment_count = comment_count + 1 where user_id = NEW.creator_id; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates - set comment_count = comment_count - 1 where user_id = OLD.creator_id; +CREATE FUNCTION user_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + user_aggregates + SET + comment_count = comment_count + 1 + WHERE + user_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates + SET + comment_count = comment_count - 1 + WHERE + user_id = OLD.creator_id; + -- If the comment gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + user_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + user_ u + LEFT JOIN comment c ON u.id = c.creator_id + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.user_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - -- If the comment gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update user_aggregates ua - set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from user_ u - left join comment c on u.id = c.creator_id - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd - where ua.user_id = OLD.creator_id; - END IF; - return null; -end $$; - -create trigger user_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure user_aggregates_comment_count(); +CREATE TRIGGER user_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_comment_count (); -- comment score -create function user_aggregates_comment_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update user_aggregates ua - set comment_score = comment_score + NEW.score - from comment c - where ua.user_id = c.creator_id and c.id = NEW.comment_id; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates ua - set comment_score = comment_score - OLD.score - from comment c - where ua.user_id = c.creator_id and c.id = OLD.comment_id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_comment_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + user_aggregates ua + SET + comment_score = comment_score + NEW.score + FROM + comment c + WHERE + ua.user_id = c.creator_id + AND c.id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates ua + SET + comment_score = comment_score - OLD.score + FROM + comment c + WHERE + ua.user_id = c.creator_id + AND c.id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; + +CREATE TRIGGER user_aggregates_comment_score + AFTER INSERT OR DELETE ON comment_like + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_comment_score (); -create trigger user_aggregates_comment_score -after insert or delete on comment_like -for each row -execute procedure user_aggregates_comment_score(); diff --git a/migrations/2020-12-04-183345_create_community_aggregates/down.sql b/migrations/2020-12-04-183345_create_community_aggregates/down.sql index fc0ffd21a..6a694e505 100644 --- a/migrations/2020-12-04-183345_create_community_aggregates/down.sql +++ b/migrations/2020-12-04-183345_create_community_aggregates/down.sql @@ -1,11 +1,13 @@ -- community aggregates -drop table community_aggregates; -drop trigger community_aggregates_community on community; -drop trigger community_aggregates_post_count on post; -drop trigger community_aggregates_comment_count on comment; -drop trigger community_aggregates_subscriber_count on community_follower; -drop function - community_aggregates_community, - community_aggregates_post_count, - community_aggregates_comment_count, - community_aggregates_subscriber_count; +DROP TABLE community_aggregates; + +DROP TRIGGER community_aggregates_community ON community; + +DROP TRIGGER community_aggregates_post_count ON post; + +DROP TRIGGER community_aggregates_comment_count ON comment; + +DROP TRIGGER community_aggregates_subscriber_count ON community_follower; + +DROP FUNCTION community_aggregates_community, community_aggregates_post_count, community_aggregates_comment_count, community_aggregates_subscriber_count; + diff --git a/migrations/2020-12-04-183345_create_community_aggregates/up.sql b/migrations/2020-12-04-183345_create_community_aggregates/up.sql index 129b58c00..2770d3d8d 100644 --- a/migrations/2020-12-04-183345_create_community_aggregates/up.sql +++ b/migrations/2020-12-04-183345_create_community_aggregates/up.sql @@ -1,138 +1,181 @@ -- Add community aggregates -create table community_aggregates ( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - subscribers bigint not null default 0, - posts bigint not null default 0, - comments bigint not null default 0, - published timestamp not null default now(), - unique (community_id) +CREATE TABLE community_aggregates ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + subscribers bigint NOT NULL DEFAULT 0, + posts bigint NOT NULL DEFAULT 0, + comments bigint NOT NULL DEFAULT 0, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (community_id) ); -insert into community_aggregates (community_id, subscribers, posts, comments, published) - select +INSERT INTO community_aggregates (community_id, subscribers, posts, comments, published) +SELECT c.id, - coalesce(cf.subs, 0) as subscribers, - coalesce(cd.posts, 0) as posts, - coalesce(cd.comments, 0) as comments, + coalesce(cf.subs, 0) AS subscribers, + coalesce(cd.posts, 0) AS posts, + coalesce(cd.comments, 0) AS comments, c.published - from community c - left join ( - select - p.community_id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from post p - left join comment ct on p.id = ct.post_id - group by p.community_id - ) cd on cd.community_id = c.id - left join ( - select - community_follower.community_id, - count(*) as subs - from community_follower - group by community_follower.community_id - ) cf on cf.community_id = c.id; +FROM + community c + LEFT JOIN ( + SELECT + p.community_id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + post p + LEFT JOIN comment ct ON p.id = ct.post_id + GROUP BY + p.community_id) cd ON cd.community_id = c.id + LEFT JOIN ( + SELECT + community_follower.community_id, + count(*) AS subs + FROM + community_follower + GROUP BY + community_follower.community_id) cf ON cf.community_id = c.id; -- Add community aggregate triggers - -- initial community add -create function community_aggregates_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into community_aggregates (community_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from community_aggregates where community_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION community_aggregates_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates (community_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates + WHERE community_id = OLD.id; + END IF; + RETURN NULL; +END +$$; + +CREATE TRIGGER community_aggregates_community + AFTER INSERT OR DELETE ON community + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_community (); -create trigger community_aggregates_community -after insert or delete on community -for each row -execute procedure community_aggregates_community(); -- post count -create function community_aggregates_post_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update community_aggregates - set posts = posts + 1 where community_id = NEW.community_id; - ELSIF (TG_OP = 'DELETE') THEN - update community_aggregates - set posts = posts - 1 where community_id = OLD.community_id; +CREATE FUNCTION community_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates + SET + posts = posts + 1 + WHERE + community_id = NEW.community_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates + SET + posts = posts - 1 + WHERE + community_id = OLD.community_id; + -- Update the counts if the post got deleted + UPDATE + community_aggregates ca + SET + posts = coalesce(cd.posts, 0), + comments = coalesce(cd.comments, 0) + FROM ( + SELECT + c.id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + community c + LEFT JOIN post p ON c.id = p.community_id + LEFT JOIN comment ct ON p.id = ct.post_id + GROUP BY + c.id) cd + WHERE + ca.community_id = OLD.community_id; + END IF; + RETURN NULL; +END +$$; - -- Update the counts if the post got deleted - update community_aggregates ca - set posts = coalesce(cd.posts, 0), - comments = coalesce(cd.comments, 0) - from ( - select - c.id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from community c - left join post p on c.id = p.community_id - left join comment ct on p.id = ct.post_id - group by c.id - ) cd - where ca.community_id = OLD.community_id; - END IF; - return null; -end $$; - -create trigger community_aggregates_post_count -after insert or delete on post -for each row -execute procedure community_aggregates_post_count(); +CREATE TRIGGER community_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_post_count (); -- comment count -create function community_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update community_aggregates ca - set comments = comments + 1 from comment c, post p - where p.id = c.post_id - and p.id = NEW.post_id - and ca.community_id = p.community_id; - ELSIF (TG_OP = 'DELETE') THEN - update community_aggregates ca - set comments = comments - 1 from comment c, post p - where p.id = c.post_id - and p.id = OLD.post_id - and ca.community_id = p.community_id; +CREATE FUNCTION community_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates ca + SET + comments = comments + 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = NEW.post_id + AND ca.community_id = p.community_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates ca + SET + comments = comments - 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = OLD.post_id + AND ca.community_id = p.community_id; + END IF; + RETURN NULL; +END +$$; - END IF; - return null; -end $$; - -create trigger community_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure community_aggregates_comment_count(); +CREATE TRIGGER community_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_comment_count (); -- subscriber count -create function community_aggregates_subscriber_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update community_aggregates - set subscribers = subscribers + 1 where community_id = NEW.community_id; - ELSIF (TG_OP = 'DELETE') THEN - update community_aggregates - set subscribers = subscribers - 1 where community_id = OLD.community_id; - END IF; - return null; -end $$; +CREATE FUNCTION community_aggregates_subscriber_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates + SET + subscribers = subscribers + 1 + WHERE + community_id = NEW.community_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates + SET + subscribers = subscribers - 1 + WHERE + community_id = OLD.community_id; + END IF; + RETURN NULL; +END +$$; -create trigger community_aggregates_subscriber_count -after insert or delete on community_follower -for each row -execute procedure community_aggregates_subscriber_count(); +CREATE TRIGGER community_aggregates_subscriber_count + AFTER INSERT OR DELETE ON community_follower + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_subscriber_count (); diff --git a/migrations/2020-12-10-152350_create_post_aggregates/down.sql b/migrations/2020-12-10-152350_create_post_aggregates/down.sql index 7b4024cda..38bfb998b 100644 --- a/migrations/2020-12-10-152350_create_post_aggregates/down.sql +++ b/migrations/2020-12-10-152350_create_post_aggregates/down.sql @@ -1,11 +1,13 @@ -- post aggregates -drop table post_aggregates; -drop trigger post_aggregates_post on post; -drop trigger post_aggregates_comment_count on comment; -drop trigger post_aggregates_score on post_like; -drop trigger post_aggregates_stickied on post; -drop function - post_aggregates_post, - post_aggregates_comment_count, - post_aggregates_score, - post_aggregates_stickied; +DROP TABLE post_aggregates; + +DROP TRIGGER post_aggregates_post ON post; + +DROP TRIGGER post_aggregates_comment_count ON comment; + +DROP TRIGGER post_aggregates_score ON post_like; + +DROP TRIGGER post_aggregates_stickied ON post; + +DROP FUNCTION post_aggregates_post, post_aggregates_comment_count, post_aggregates_score, post_aggregates_stickied; + diff --git a/migrations/2020-12-10-152350_create_post_aggregates/up.sql b/migrations/2020-12-10-152350_create_post_aggregates/up.sql index fcb3a9390..7ee817dc8 100644 --- a/migrations/2020-12-10-152350_create_post_aggregates/up.sql +++ b/migrations/2020-12-10-152350_create_post_aggregates/up.sql @@ -1,140 +1,187 @@ -- Add post aggregates -create table post_aggregates ( - id serial primary key, - post_id int references post on update cascade on delete cascade not null, - comments bigint not null default 0, - score bigint not null default 0, - upvotes bigint not null default 0, - downvotes bigint not null default 0, - stickied boolean not null default false, - published timestamp not null default now(), - newest_comment_time timestamp not null default now(), - unique (post_id) +CREATE TABLE post_aggregates ( + id serial PRIMARY KEY, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + comments bigint NOT NULL DEFAULT 0, + score bigint NOT NULL DEFAULT 0, + upvotes bigint NOT NULL DEFAULT 0, + downvotes bigint NOT NULL DEFAULT 0, + stickied boolean NOT NULL DEFAULT FALSE, + published timestamp NOT NULL DEFAULT now(), + newest_comment_time timestamp NOT NULL DEFAULT now(), + UNIQUE (post_id) ); -insert into post_aggregates (post_id, comments, score, upvotes, downvotes, stickied, published, newest_comment_time) - select +INSERT INTO post_aggregates (post_id, comments, score, upvotes, downvotes, stickied, published, newest_comment_time) +SELECT p.id, - coalesce(ct.comments, 0::bigint) as comments, - coalesce(pl.score, 0::bigint) as score, - coalesce(pl.upvotes, 0::bigint) as upvotes, - coalesce(pl.downvotes, 0::bigint) as downvotes, + coalesce(ct.comments, 0::bigint) AS comments, + coalesce(pl.score, 0::bigint) AS score, + coalesce(pl.upvotes, 0::bigint) AS upvotes, + coalesce(pl.downvotes, 0::bigint) AS downvotes, p.stickied, p.published, - greatest(ct.recent_comment_time, p.published) as newest_activity_time - from post p - left join ( - select comment.post_id, - count(*) as comments, - max(comment.published) as recent_comment_time - from comment - group by comment.post_id - ) ct on ct.post_id = p.id - left join ( - select post_like.post_id, - sum(post_like.score) as score, - sum(post_like.score) filter (where post_like.score = 1) as upvotes, - -sum(post_like.score) filter (where post_like.score = '-1'::integer) as downvotes - from post_like - group by post_like.post_id - ) pl on pl.post_id = p.id; + greatest (ct.recent_comment_time, p.published) AS newest_activity_time +FROM + post p + LEFT JOIN ( + SELECT + comment.post_id, + count(*) AS comments, + max(comment.published) AS recent_comment_time + FROM + comment + GROUP BY + comment.post_id) ct ON ct.post_id = p.id + LEFT JOIN ( + SELECT + post_like.post_id, + sum(post_like.score) AS score, + sum(post_like.score) FILTER (WHERE post_like.score = 1) AS upvotes, + - sum(post_like.score) FILTER (WHERE post_like.score = '-1'::integer) AS downvotes + FROM + post_like + GROUP BY + post_like.post_id) pl ON pl.post_id = p.id; -- Add community aggregate triggers - -- initial post add -create function post_aggregates_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into post_aggregates (post_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from post_aggregates where post_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION post_aggregates_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates (post_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates + WHERE post_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger post_aggregates_post -after insert or delete on post -for each row -execute procedure post_aggregates_post(); +CREATE TRIGGER post_aggregates_post + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_post (); -- comment count -create function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1 - where pa.post_id = NEW.post_id; +CREATE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1 + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id + AND published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time = NEW.published - where pa.post_id = NEW.post_id - and published > ('now'::timestamp - '2 days'::interval); - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; - -create trigger post_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure post_aggregates_comment_count(); +CREATE TRIGGER post_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_comment_count (); -- post score -create function post_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end - where pa.post_id = NEW.post_id; +CREATE FUNCTION post_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + pa.post_id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - - END IF; - return null; -end $$; - -create trigger post_aggregates_score -after insert or delete on post_like -for each row -execute procedure post_aggregates_score(); +CREATE TRIGGER post_aggregates_score + AFTER INSERT OR DELETE ON post_like + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_score (); -- post stickied -create function post_aggregates_stickied() -returns trigger language plpgsql -as $$ -begin - update post_aggregates pa - set stickied = NEW.stickied - where pa.post_id = NEW.id; +CREATE FUNCTION post_aggregates_stickied () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + post_aggregates pa + SET + stickied = NEW.stickied + WHERE + pa.post_id = NEW.id; + RETURN NULL; +END +$$; - return null; -end $$; +CREATE TRIGGER post_aggregates_stickied + AFTER UPDATE ON post + FOR EACH ROW + WHEN (OLD.stickied IS DISTINCT FROM NEW.stickied) + EXECUTE PROCEDURE post_aggregates_stickied (); -create trigger post_aggregates_stickied -after update on post -for each row -when (OLD.stickied is distinct from NEW.stickied) -execute procedure post_aggregates_stickied(); diff --git a/migrations/2020-12-14-020038_create_comment_aggregates/down.sql b/migrations/2020-12-14-020038_create_comment_aggregates/down.sql index 6fd9ddc25..1b3809ba2 100644 --- a/migrations/2020-12-14-020038_create_comment_aggregates/down.sql +++ b/migrations/2020-12-14-020038_create_comment_aggregates/down.sql @@ -1,7 +1,9 @@ -- comment aggregates -drop table comment_aggregates; -drop trigger comment_aggregates_comment on comment; -drop trigger comment_aggregates_score on comment_like; -drop function - comment_aggregates_comment, - comment_aggregates_score; +DROP TABLE comment_aggregates; + +DROP TRIGGER comment_aggregates_comment ON comment; + +DROP TRIGGER comment_aggregates_score ON comment_like; + +DROP FUNCTION comment_aggregates_comment, comment_aggregates_score; + diff --git a/migrations/2020-12-14-020038_create_comment_aggregates/up.sql b/migrations/2020-12-14-020038_create_comment_aggregates/up.sql index f9cae6b37..25a9414f8 100644 --- a/migrations/2020-12-14-020038_create_comment_aggregates/up.sql +++ b/migrations/2020-12-14-020038_create_comment_aggregates/up.sql @@ -1,84 +1,118 @@ -- Add comment aggregates -create table comment_aggregates ( - id serial primary key, - comment_id int references comment on update cascade on delete cascade not null, - score bigint not null default 0, - upvotes bigint not null default 0, - downvotes bigint not null default 0, - published timestamp not null default now(), - unique (comment_id) +CREATE TABLE comment_aggregates ( + id serial PRIMARY KEY, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + score bigint NOT NULL DEFAULT 0, + upvotes bigint NOT NULL DEFAULT 0, + downvotes bigint NOT NULL DEFAULT 0, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (comment_id) ); -insert into comment_aggregates (comment_id, score, upvotes, downvotes, published) - select +INSERT INTO comment_aggregates (comment_id, score, upvotes, downvotes, published) +SELECT c.id, COALESCE(cl.total, 0::bigint) AS score, COALESCE(cl.up, 0::bigint) AS upvotes, COALESCE(cl.down, 0::bigint) AS downvotes, c.published - from comment c - left join ( select l.comment_id as id, - sum(l.score) as total, - count( - case - when l.score = 1 then 1 - else null::integer - end) as up, - count( - case - when l.score = '-1'::integer then 1 - else null::integer - end) as down - from comment_like l - group by l.comment_id) cl on cl.id = c.id; +FROM + comment c + LEFT JOIN ( + SELECT + l.comment_id AS id, + sum(l.score) AS total, + count( + CASE WHEN l.score = 1 THEN + 1 + ELSE + NULL::integer + END) AS up, + count( + CASE WHEN l.score = '-1'::integer THEN + 1 + ELSE + NULL::integer + END) AS down + FROM + comment_like l + GROUP BY + l.comment_id) cl ON cl.id = c.id; -- Add comment aggregate triggers - -- initial comment add -create function comment_aggregates_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into comment_aggregates (comment_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from comment_aggregates where comment_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION comment_aggregates_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates (comment_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates + WHERE comment_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger comment_aggregates_comment -after insert or delete on comment -for each row -execute procedure comment_aggregates_comment(); +CREATE TRIGGER comment_aggregates_comment + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE comment_aggregates_comment (); -- comment score -create function comment_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update comment_aggregates ca - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end - where ca.comment_id = NEW.comment_id; +CREATE FUNCTION comment_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + comment_aggregates ca + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + ca.comment_id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to comment because that comment may not exist anymore + UPDATE + comment_aggregates ca + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END + FROM + comment c + WHERE + ca.comment_id = c.id + AND ca.comment_id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'DELETE') THEN - -- Join to comment because that comment may not exist anymore - update comment_aggregates ca - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end - from comment c - where ca.comment_id = c.id - and ca.comment_id = OLD.comment_id; +CREATE TRIGGER comment_aggregates_score + AFTER INSERT OR DELETE ON comment_like + FOR EACH ROW + EXECUTE PROCEDURE comment_aggregates_score (); - END IF; - return null; -end $$; - -create trigger comment_aggregates_score -after insert or delete on comment_like -for each row -execute procedure comment_aggregates_score(); diff --git a/migrations/2020-12-17-030456_create_alias_views/down.sql b/migrations/2020-12-17-030456_create_alias_views/down.sql index 66ded96e5..ac9172694 100644 --- a/migrations/2020-12-17-030456_create_alias_views/down.sql +++ b/migrations/2020-12-17-030456_create_alias_views/down.sql @@ -1 +1,2 @@ -drop view user_alias_1, user_alias_2, comment_alias_1; +DROP VIEW user_alias_1, user_alias_2, comment_alias_1; + diff --git a/migrations/2020-12-17-030456_create_alias_views/up.sql b/migrations/2020-12-17-030456_create_alias_views/up.sql index 3d3b1b430..8eb35fc93 100644 --- a/migrations/2020-12-17-030456_create_alias_views/up.sql +++ b/migrations/2020-12-17-030456_create_alias_views/up.sql @@ -1,7 +1,21 @@ --- Some view that act as aliases +-- Some view that act as aliases -- unfortunately necessary, since diesel doesn't have self joins -- or alias support yet -create view user_alias_1 as select * from user_; -create view user_alias_2 as select * from user_; -create view comment_alias_1 as select * from comment; +CREATE VIEW user_alias_1 AS +SELECT + * +FROM + user_; + +CREATE VIEW user_alias_2 AS +SELECT + * +FROM + user_; + +CREATE VIEW comment_alias_1 AS +SELECT + * +FROM + comment; diff --git a/migrations/2020-12-17-031053_remove_fast_tables_and_views/down.sql b/migrations/2020-12-17-031053_remove_fast_tables_and_views/down.sql index 1c5d77670..275f4b610 100644 --- a/migrations/2020-12-17-031053_remove_fast_tables_and_views/down.sql +++ b/migrations/2020-12-17-031053_remove_fast_tables_and_views/down.sql @@ -1,4 +1,8 @@ -- There is no restore for this, it would require every view, table, index, etc. -- If you want to save past this point, you should make a DB backup. +SELECT + * +FROM + user_ +LIMIT 1; -select * from user_ limit 1; diff --git a/migrations/2020-12-17-031053_remove_fast_tables_and_views/up.sql b/migrations/2020-12-17-031053_remove_fast_tables_and_views/up.sql index cafa48ce8..e7927737d 100644 --- a/migrations/2020-12-17-031053_remove_fast_tables_and_views/up.sql +++ b/migrations/2020-12-17-031053_remove_fast_tables_and_views/up.sql @@ -1,64 +1,26 @@ -- Drop triggers -drop trigger if exists refresh_comment on comment; -drop trigger if exists refresh_comment_like on comment_like; -drop trigger if exists refresh_community on community; -drop trigger if exists refresh_community_follower on community_follower; -drop trigger if exists refresh_community_user_ban on community_user_ban; -drop trigger if exists refresh_post on post; -drop trigger if exists refresh_post_like on post_like; -drop trigger if exists refresh_user on user_; +DROP TRIGGER IF EXISTS refresh_comment ON comment; + +DROP TRIGGER IF EXISTS refresh_comment_like ON comment_like; + +DROP TRIGGER IF EXISTS refresh_community ON community; + +DROP TRIGGER IF EXISTS refresh_community_follower ON community_follower; + +DROP TRIGGER IF EXISTS refresh_community_user_ban ON community_user_ban; + +DROP TRIGGER IF EXISTS refresh_post ON post; + +DROP TRIGGER IF EXISTS refresh_post_like ON post_like; + +DROP TRIGGER IF EXISTS refresh_user ON user_; -- Drop functions -drop function if exists -refresh_comment, -refresh_comment_like, -refresh_community, -refresh_community_follower, -refresh_community_user_ban, -refresh_post, -refresh_post_like, -refresh_private_message, -refresh_user -cascade; +DROP FUNCTION IF EXISTS refresh_comment, refresh_comment_like, refresh_community, refresh_community_follower, refresh_community_user_ban, refresh_post, refresh_post_like, refresh_private_message, refresh_user CASCADE; -- Drop views -drop view if exists -comment_aggregates_view, -comment_fast_view, -comment_report_view, -comment_view, -community_aggregates_view, -community_fast_view, -community_follower_view, -community_moderator_view, -community_user_ban_view, -community_view, -mod_add_community_view, -mod_add_view, -mod_ban_from_community_view, -mod_ban_view, -mod_lock_post_view, -mod_remove_comment_view, -mod_remove_community_view, -mod_remove_post_view, -mod_sticky_post_view, -post_aggregates_view, -post_fast_view, -post_report_view, -post_view, -private_message_view, -reply_fast_view, -site_view, -user_mention_fast_view, -user_mention_view, -user_view -cascade; +DROP VIEW IF EXISTS comment_aggregates_view, comment_fast_view, comment_report_view, comment_view, community_aggregates_view, community_fast_view, community_follower_view, community_moderator_view, community_user_ban_view, community_view, mod_add_community_view, mod_add_view, mod_ban_from_community_view, mod_ban_view, mod_lock_post_view, mod_remove_comment_view, mod_remove_community_view, mod_remove_post_view, mod_sticky_post_view, post_aggregates_view, post_fast_view, post_report_view, post_view, private_message_view, reply_fast_view, site_view, user_mention_fast_view, user_mention_view, user_view CASCADE; -- Drop fast tables -drop table if exists -comment_aggregates_fast, -community_aggregates_fast, -post_aggregates_fast, -user_fast -cascade; +DROP TABLE IF EXISTS comment_aggregates_fast, community_aggregates_fast, post_aggregates_fast, user_fast CASCADE; diff --git a/migrations/2021-01-05-200932_add_hot_rank_indexes/down.sql b/migrations/2021-01-05-200932_add_hot_rank_indexes/down.sql index 55e833323..85267bf73 100644 --- a/migrations/2021-01-05-200932_add_hot_rank_indexes/down.sql +++ b/migrations/2021-01-05-200932_add_hot_rank_indexes/down.sql @@ -1,28 +1,13 @@ -- Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity -create or replace function hot_rank( - score numeric, - published timestamp without time zone) -returns integer as $$ -begin - -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 - return floor(10000*log(greatest(1,score+3)) / power(((EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600) + 2), 1.8))::integer; -end; $$ +CREATE OR REPLACE FUNCTION hot_rank (score numeric, published timestamp without time zone) + RETURNS integer + AS $$ +BEGIN + -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 + RETURN floor(10000 * log(greatest (1, score + 3)) / power(((EXTRACT(EPOCH FROM (timezone('utc', now()) - published)) / 3600) + 2), 1.8))::integer; +END; +$$ LANGUAGE plpgsql; -drop index - idx_post_aggregates_hot, - idx_post_aggregates_stickied_hot, - idx_post_aggregates_active, - idx_post_aggregates_stickied_active, - idx_post_aggregates_score, - idx_post_aggregates_stickied_score, - idx_post_aggregates_published, - idx_post_aggregates_stickied_published, - idx_comment_published, - idx_comment_aggregates_hot, - idx_comment_aggregates_score, - idx_user_published, - idx_user_aggregates_comment_score, - idx_community_published, - idx_community_aggregates_hot, - idx_community_aggregates_subscribers; +DROP INDEX idx_post_aggregates_hot, idx_post_aggregates_stickied_hot, idx_post_aggregates_active, idx_post_aggregates_stickied_active, idx_post_aggregates_score, idx_post_aggregates_stickied_score, idx_post_aggregates_published, idx_post_aggregates_stickied_published, idx_comment_published, idx_comment_aggregates_hot, idx_comment_aggregates_score, idx_user_published, idx_user_aggregates_comment_score, idx_community_published, idx_community_aggregates_hot, idx_community_aggregates_subscribers; + diff --git a/migrations/2021-01-05-200932_add_hot_rank_indexes/up.sql b/migrations/2021-01-05-200932_add_hot_rank_indexes/up.sql index f4d414710..88eb0f4be 100644 --- a/migrations/2021-01-05-200932_add_hot_rank_indexes/up.sql +++ b/migrations/2021-01-05-200932_add_hot_rank_indexes/up.sql @@ -1,49 +1,52 @@ -- Need to add immutable to the hot_rank function in order to index by it - -- Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity -create or replace function hot_rank( - score numeric, - published timestamp without time zone) -returns integer as $$ -begin - -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 - return floor(10000*log(greatest(1,score+3)) / power(((EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600) + 2), 1.8))::integer; -end; $$ +CREATE OR REPLACE FUNCTION hot_rank (score numeric, published timestamp without time zone) + RETURNS integer + AS $$ +BEGIN + -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 + RETURN floor(10000 * log(greatest (1, score + 3)) / power(((EXTRACT(EPOCH FROM (timezone('utc', now()) - published)) / 3600) + 2), 1.8))::integer; +END; +$$ LANGUAGE plpgsql IMMUTABLE; -- Post_aggregates -create index idx_post_aggregates_stickied_hot on post_aggregates (stickied desc, hot_rank(score, published) desc, published desc); -create index idx_post_aggregates_hot on post_aggregates (hot_rank(score, published) desc, published desc); +CREATE INDEX idx_post_aggregates_stickied_hot ON post_aggregates (stickied DESC, hot_rank (score, published) DESC, published DESC); -create index idx_post_aggregates_stickied_active on post_aggregates (stickied desc, hot_rank(score, newest_comment_time) desc, newest_comment_time desc); -create index idx_post_aggregates_active on post_aggregates (hot_rank(score, newest_comment_time) desc, newest_comment_time desc); +CREATE INDEX idx_post_aggregates_hot ON post_aggregates (hot_rank (score, published) DESC, published DESC); -create index idx_post_aggregates_stickied_score on post_aggregates (stickied desc, score desc); -create index idx_post_aggregates_score on post_aggregates (score desc); +CREATE INDEX idx_post_aggregates_stickied_active ON post_aggregates (stickied DESC, hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); -create index idx_post_aggregates_stickied_published on post_aggregates (stickied desc, published desc); -create index idx_post_aggregates_published on post_aggregates (published desc); +CREATE INDEX idx_post_aggregates_active ON post_aggregates (hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_stickied_score ON post_aggregates (stickied DESC, score DESC); + +CREATE INDEX idx_post_aggregates_score ON post_aggregates (score DESC); + +CREATE INDEX idx_post_aggregates_stickied_published ON post_aggregates (stickied DESC, published DESC); + +CREATE INDEX idx_post_aggregates_published ON post_aggregates (published DESC); -- Comment -create index idx_comment_published on comment (published desc); +CREATE INDEX idx_comment_published ON comment (published DESC); -- Comment_aggregates -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank(score, published) desc, published desc); -create index idx_comment_aggregates_score on comment_aggregates (score desc); +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank (score, published) DESC, published DESC); + +CREATE INDEX idx_comment_aggregates_score ON comment_aggregates (score DESC); -- User -create index idx_user_published on user_ (published desc); +CREATE INDEX idx_user_published ON user_ (published DESC); -- User_aggregates -create index idx_user_aggregates_comment_score on user_aggregates (comment_score desc); +CREATE INDEX idx_user_aggregates_comment_score ON user_aggregates (comment_score DESC); -- Community -create index idx_community_published on community (published desc); +CREATE INDEX idx_community_published ON community (published DESC); -- Community_aggregates -create index idx_community_aggregates_hot on community_aggregates (hot_rank(subscribers, published) desc, published desc); -create index idx_community_aggregates_subscribers on community_aggregates (subscribers desc); - +CREATE INDEX idx_community_aggregates_hot ON community_aggregates (hot_rank (subscribers, published) DESC, published DESC); +CREATE INDEX idx_community_aggregates_subscribers ON community_aggregates (subscribers DESC); diff --git a/migrations/2021-01-26-173850_default_actor_id/down.sql b/migrations/2021-01-26-173850_default_actor_id/down.sql index fb612743e..80092cab9 100644 --- a/migrations/2021-01-26-173850_default_actor_id/down.sql +++ b/migrations/2021-01-26-173850_default_actor_id/down.sql @@ -1,6 +1,10 @@ -create or replace function generate_unique_changeme() -returns text language sql -as $$ - select 'changeme_' || string_agg (substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil (random() * 62)::integer, 1), '') - from generate_series(1, 20) -$$; \ No newline at end of file +CREATE OR REPLACE FUNCTION generate_unique_changeme () + RETURNS text + LANGUAGE sql + AS $$ + SELECT + 'changeme_' || string_agg(substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil(random() * 62)::integer, 1), '') + FROM + generate_series(1, 20) +$$; + diff --git a/migrations/2021-01-26-173850_default_actor_id/up.sql b/migrations/2021-01-26-173850_default_actor_id/up.sql index 4370c4a52..00aa1c719 100644 --- a/migrations/2021-01-26-173850_default_actor_id/up.sql +++ b/migrations/2021-01-26-173850_default_actor_id/up.sql @@ -1,6 +1,10 @@ -create or replace function generate_unique_changeme() -returns text language sql -as $$ - select 'http://changeme_' || string_agg (substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil (random() * 62)::integer, 1), '') - from generate_series(1, 20) -$$; \ No newline at end of file +CREATE OR REPLACE FUNCTION generate_unique_changeme () + RETURNS text + LANGUAGE sql + AS $$ + SELECT + 'http://changeme_' || string_agg(substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil(random() * 62)::integer, 1), '') + FROM + generate_series(1, 20) +$$; + diff --git a/migrations/2021-01-27-202728_active_users_monthly/down.sql b/migrations/2021-01-27-202728_active_users_monthly/down.sql index bc3d46a54..e5d636892 100644 --- a/migrations/2021-01-27-202728_active_users_monthly/down.sql +++ b/migrations/2021-01-27-202728_active_users_monthly/down.sql @@ -1,14 +1,16 @@ -alter table site_aggregates - drop column users_active_day, - drop column users_active_week, - drop column users_active_month, - drop column users_active_half_year; +ALTER TABLE site_aggregates + DROP COLUMN users_active_day, + DROP COLUMN users_active_week, + DROP COLUMN users_active_month, + DROP COLUMN users_active_half_year; -alter table community_aggregates - drop column users_active_day, - drop column users_active_week, - drop column users_active_month, - drop column users_active_half_year; +ALTER TABLE community_aggregates + DROP COLUMN users_active_day, + DROP COLUMN users_active_week, + DROP COLUMN users_active_month, + DROP COLUMN users_active_half_year; + +DROP FUNCTION site_aggregates_activity (i text); + +DROP FUNCTION community_aggregates_activity (i text); -drop function site_aggregates_activity(i text); -drop function community_aggregates_activity(i text); diff --git a/migrations/2021-01-27-202728_active_users_monthly/up.sql b/migrations/2021-01-27-202728_active_users_monthly/up.sql index 9248ae868..63ca51d1e 100644 --- a/migrations/2021-01-27-202728_active_users_monthly/up.sql +++ b/migrations/2021-01-27-202728_active_users_monthly/up.sql @@ -1,89 +1,162 @@ -- Add monthly and half yearly active columns for site and community aggregates - -- These columns don't need to be updated with a trigger, so they're saved daily via queries -alter table site_aggregates add column users_active_day bigint not null default 0; -alter table site_aggregates add column users_active_week bigint not null default 0; -alter table site_aggregates add column users_active_month bigint not null default 0; -alter table site_aggregates add column users_active_half_year bigint not null default 0; +ALTER TABLE site_aggregates + ADD COLUMN users_active_day bigint NOT NULL DEFAULT 0; -alter table community_aggregates add column users_active_day bigint not null default 0; -alter table community_aggregates add column users_active_week bigint not null default 0; -alter table community_aggregates add column users_active_month bigint not null default 0; -alter table community_aggregates add column users_active_half_year bigint not null default 0; +ALTER TABLE site_aggregates + ADD COLUMN users_active_week bigint NOT NULL DEFAULT 0; -create or replace function site_aggregates_activity(i text) -returns int -language plpgsql -as -$$ -declare - count_ integer; -begin - select count(*) - into count_ - from ( - select c.creator_id from comment c - inner join user_ u on c.creator_id = u.id - where c.published > ('now'::timestamp - i::interval) - and u.local = true - union - select p.creator_id from post p - inner join user_ u on p.creator_id = u.id - where p.published > ('now'::timestamp - i::interval) - and u.local = true - ) a; - return count_; -end; +ALTER TABLE site_aggregates + ADD COLUMN users_active_month bigint NOT NULL DEFAULT 0; + +ALTER TABLE site_aggregates + ADD COLUMN users_active_half_year bigint NOT NULL DEFAULT 0; + +ALTER TABLE community_aggregates + ADD COLUMN users_active_day bigint NOT NULL DEFAULT 0; + +ALTER TABLE community_aggregates + ADD COLUMN users_active_week bigint NOT NULL DEFAULT 0; + +ALTER TABLE community_aggregates + ADD COLUMN users_active_month bigint NOT NULL DEFAULT 0; + +ALTER TABLE community_aggregates + ADD COLUMN users_active_half_year bigint NOT NULL DEFAULT 0; + +CREATE OR REPLACE FUNCTION site_aggregates_activity (i text) + RETURNS int + LANGUAGE plpgsql + AS $$ +DECLARE + count_ integer; +BEGIN + SELECT + count(*) INTO count_ + FROM ( + SELECT + c.creator_id + FROM + comment c + INNER JOIN user_ u ON c.creator_id = u.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + UNION + SELECT + p.creator_id + FROM + post p + INNER JOIN user_ u ON p.creator_id = u.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND u.local = TRUE) a; + RETURN count_; +END; $$; -update site_aggregates -set users_active_day = (select * from site_aggregates_activity('1 day')); +UPDATE + site_aggregates +SET + users_active_day = ( + SELECT + * + FROM + site_aggregates_activity ('1 day')); -update site_aggregates -set users_active_week = (select * from site_aggregates_activity('1 week')); +UPDATE + site_aggregates +SET + users_active_week = ( + SELECT + * + FROM + site_aggregates_activity ('1 week')); -update site_aggregates -set users_active_month = (select * from site_aggregates_activity('1 month')); +UPDATE + site_aggregates +SET + users_active_month = ( + SELECT + * + FROM + site_aggregates_activity ('1 month')); -update site_aggregates -set users_active_half_year = (select * from site_aggregates_activity('6 months')); +UPDATE + site_aggregates +SET + users_active_half_year = ( + SELECT + * + FROM + site_aggregates_activity ('6 months')); -create or replace function community_aggregates_activity(i text) -returns table(count_ bigint, community_id_ integer) -language plpgsql -as -$$ -begin - return query - select count(*), community_id - from ( - select c.creator_id, p.community_id from comment c - inner join post p on c.post_id = p.id - where c.published > ('now'::timestamp - i::interval) - union - select p.creator_id, p.community_id from post p - where p.published > ('now'::timestamp - i::interval) - ) a - group by community_id; -end; +CREATE OR REPLACE FUNCTION community_aggregates_activity (i text) + RETURNS TABLE ( + count_ bigint, + community_id_ integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN query + SELECT + count(*), + community_id + FROM ( + SELECT + c.creator_id, + p.community_id + FROM + comment c + INNER JOIN post p ON c.post_id = p.id + WHERE + c.published > ('now'::timestamp - i::interval) + UNION + SELECT + p.creator_id, + p.community_id + FROM + post p + WHERE + p.published > ('now'::timestamp - i::interval)) a +GROUP BY + community_id; +END; $$; -update community_aggregates ca -set users_active_day = mv.count_ -from community_aggregates_activity('1 day') mv -where ca.community_id = mv.community_id_; +UPDATE + community_aggregates ca +SET + users_active_day = mv.count_ +FROM + community_aggregates_activity ('1 day') mv +WHERE + ca.community_id = mv.community_id_; -update community_aggregates ca -set users_active_week = mv.count_ -from community_aggregates_activity('1 week') mv -where ca.community_id = mv.community_id_; +UPDATE + community_aggregates ca +SET + users_active_week = mv.count_ +FROM + community_aggregates_activity ('1 week') mv +WHERE + ca.community_id = mv.community_id_; -update community_aggregates ca -set users_active_month = mv.count_ -from community_aggregates_activity('1 month') mv -where ca.community_id = mv.community_id_; +UPDATE + community_aggregates ca +SET + users_active_month = mv.count_ +FROM + community_aggregates_activity ('1 month') mv +WHERE + ca.community_id = mv.community_id_; + +UPDATE + community_aggregates ca +SET + users_active_half_year = mv.count_ +FROM + community_aggregates_activity ('6 months') mv +WHERE + ca.community_id = mv.community_id_; -update community_aggregates ca -set users_active_half_year = mv.count_ -from community_aggregates_activity('6 months') mv -where ca.community_id = mv.community_id_; diff --git a/migrations/2021-01-31-050334_add_forum_sort_index/down.sql b/migrations/2021-01-31-050334_add_forum_sort_index/down.sql index 9de296983..a81fc6c0a 100644 --- a/migrations/2021-01-31-050334_add_forum_sort_index/down.sql +++ b/migrations/2021-01-31-050334_add_forum_sort_index/down.sql @@ -1 +1,2 @@ -drop index idx_post_aggregates_comments; +DROP INDEX idx_post_aggregates_comments; + diff --git a/migrations/2021-01-31-050334_add_forum_sort_index/up.sql b/migrations/2021-01-31-050334_add_forum_sort_index/up.sql index 610873888..18013f48a 100644 --- a/migrations/2021-01-31-050334_add_forum_sort_index/up.sql +++ b/migrations/2021-01-31-050334_add_forum_sort_index/up.sql @@ -1 +1,2 @@ -create index idx_post_aggregates_comments on post_aggregates (comments desc); +CREATE INDEX idx_post_aggregates_comments ON post_aggregates (comments DESC); + diff --git a/migrations/2021-02-02-153240_apub_columns/down.sql b/migrations/2021-02-02-153240_apub_columns/down.sql index 248eb9b80..a5ff8edcf 100644 --- a/migrations/2021-02-02-153240_apub_columns/down.sql +++ b/migrations/2021-02-02-153240_apub_columns/down.sql @@ -1,6 +1,15 @@ -ALTER TABLE community DROP COLUMN followers_url; -ALTER TABLE community DROP COLUMN inbox_url; -ALTER TABLE community DROP COLUMN shared_inbox_url; +ALTER TABLE community + DROP COLUMN followers_url; + +ALTER TABLE community + DROP COLUMN inbox_url; + +ALTER TABLE community + DROP COLUMN shared_inbox_url; + +ALTER TABLE user_ + DROP COLUMN inbox_url; + +ALTER TABLE user_ + DROP COLUMN shared_inbox_url; -ALTER TABLE user_ DROP COLUMN inbox_url; -ALTER TABLE user_ DROP COLUMN shared_inbox_url; \ No newline at end of file diff --git a/migrations/2021-02-02-153240_apub_columns/up.sql b/migrations/2021-02-02-153240_apub_columns/up.sql index 48f3b20e5..69e99cb2e 100644 --- a/migrations/2021-02-02-153240_apub_columns/up.sql +++ b/migrations/2021-02-02-153240_apub_columns/up.sql @@ -1,10 +1,24 @@ -ALTER TABLE community ADD COLUMN followers_url varchar(255) NOT NULL DEFAULT generate_unique_changeme(); -ALTER TABLE community ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme(); -ALTER TABLE community ADD COLUMN shared_inbox_url varchar(255); +ALTER TABLE community + ADD COLUMN followers_url varchar(255) NOT NULL DEFAULT generate_unique_changeme (); -ALTER TABLE user_ ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme(); -ALTER TABLE user_ ADD COLUMN shared_inbox_url varchar(255); +ALTER TABLE community + ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme (); + +ALTER TABLE community + ADD COLUMN shared_inbox_url varchar(255); + +ALTER TABLE user_ + ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme (); + +ALTER TABLE user_ + ADD COLUMN shared_inbox_url varchar(255); + +ALTER TABLE community + ADD CONSTRAINT idx_community_followers_url UNIQUE (followers_url); + +ALTER TABLE community + ADD CONSTRAINT idx_community_inbox_url UNIQUE (inbox_url); + +ALTER TABLE user_ + ADD CONSTRAINT idx_user_inbox_url UNIQUE (inbox_url); -ALTER TABLE community ADD CONSTRAINT idx_community_followers_url UNIQUE (followers_url); -ALTER TABLE community ADD CONSTRAINT idx_community_inbox_url UNIQUE (inbox_url); -ALTER TABLE user_ ADD CONSTRAINT idx_user_inbox_url UNIQUE (inbox_url); diff --git a/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql b/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql index 75f9aea3a..acfd6d12b 100644 --- a/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql +++ b/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql @@ -1,33 +1,43 @@ -drop index idx_post_aggregates_newest_comment_time, -idx_post_aggregates_stickied_newest_comment_time, -idx_post_aggregates_stickied_comments; +DROP INDEX idx_post_aggregates_newest_comment_time, idx_post_aggregates_stickied_newest_comment_time, idx_post_aggregates_stickied_comments; -alter table post_aggregates drop column newest_comment_time; +ALTER TABLE post_aggregates + DROP COLUMN newest_comment_time; -alter table post_aggregates rename column newest_comment_time_necro to newest_comment_time; +ALTER TABLE post_aggregates RENAME COLUMN newest_comment_time_necro TO newest_comment_time; -create or replace function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1 - where pa.post_id = NEW.post_id; - - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time = NEW.published - where pa.post_id = NEW.post_id - and published > ('now'::timestamp - '2 days'::interval); - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1 + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id + AND published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; diff --git a/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql b/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql index 5452fbae4..70d6f30a0 100644 --- a/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql +++ b/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql @@ -1,43 +1,60 @@ -- First rename current newest comment time to newest_comment_time_necro -- necro means that time is limited to 2 days, whereas newest_comment_time ignores that. -alter table post_aggregates rename column newest_comment_time to newest_comment_time_necro; +ALTER TABLE post_aggregates RENAME COLUMN newest_comment_time TO newest_comment_time_necro; -- Add the newest_comment_time column -alter table post_aggregates add column newest_comment_time timestamp not null default now(); +ALTER TABLE post_aggregates + ADD COLUMN newest_comment_time timestamp NOT NULL DEFAULT now(); -- Set the current newest_comment_time based on the old ones -update post_aggregates set newest_comment_time = newest_comment_time_necro; +UPDATE + post_aggregates +SET + newest_comment_time = newest_comment_time_necro; -- Add the indexes for this new column -create index idx_post_aggregates_newest_comment_time on post_aggregates (newest_comment_time desc); -create index idx_post_aggregates_stickied_newest_comment_time on post_aggregates (stickied desc, newest_comment_time desc); +CREATE INDEX idx_post_aggregates_newest_comment_time ON post_aggregates (newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_stickied_newest_comment_time ON post_aggregates (stickied DESC, newest_comment_time DESC); -- Forgot to add index w/ stickied first for most comments: -create index idx_post_aggregates_stickied_comments on post_aggregates (stickied desc, comments desc); +CREATE INDEX idx_post_aggregates_stickied_comments ON post_aggregates (stickied DESC, comments DESC); -- Alter the comment trigger to set the newest_comment_time, and newest_comment_time_necro -create or replace function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1, - newest_comment_time = NEW.published - where pa.post_id = NEW.post_id; +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1, + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time_necro = NEW.published + WHERE + pa.post_id = NEW.post_id + AND published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time_necro = NEW.published - where pa.post_id = NEW.post_id - and published > ('now'::timestamp - '2 days'::interval); - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; diff --git a/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/down.sql b/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/down.sql index 227c3ec22..94e981dd0 100644 --- a/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/down.sql +++ b/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/down.sql @@ -1,35 +1,48 @@ -create or replace function comment_aggregates_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into comment_aggregates (comment_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from comment_aggregates where comment_id = OLD.id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION comment_aggregates_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates (comment_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates + WHERE comment_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create or replace function post_aggregates_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into post_aggregates (post_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from post_aggregates where post_id = OLD.id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates (post_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates + WHERE post_id = OLD.id; + END IF; + RETURN NULL; +END +$$; + +CREATE OR REPLACE FUNCTION community_aggregates_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates (community_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates + WHERE community_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create or replace function community_aggregates_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into community_aggregates (community_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from community_aggregates where community_id = OLD.id; - END IF; - return null; -end $$; diff --git a/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/up.sql b/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/up.sql index c195daad4..9a942aa46 100644 --- a/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/up.sql +++ b/migrations/2021-02-13-210612_set_correct_aggregates_time_columns/up.sql @@ -1,39 +1,51 @@ --- The published and updated columns on the aggregates tables are using now(), +-- The published and updated columns on the aggregates tables are using now(), -- when they should use the correct published or updated columns -- This is mainly a problem with federated posts being fetched +CREATE OR REPLACE FUNCTION comment_aggregates_comment () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO comment_aggregates (comment_id, published) + VALUES (NEW.id, NEW.published); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM comment_aggregates + WHERE comment_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create or replace function comment_aggregates_comment() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into comment_aggregates (comment_id, published) values (NEW.id, NEW.published); - ELSIF (TG_OP = 'DELETE') THEN - delete from comment_aggregates where comment_id = OLD.id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_post () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro) + VALUES (NEW.id, NEW.published, NEW.published, NEW.published); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM post_aggregates + WHERE post_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create or replace function post_aggregates_post() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro) values (NEW.id, NEW.published, NEW.published, NEW.published); - ELSIF (TG_OP = 'DELETE') THEN - delete from post_aggregates where post_id = OLD.id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION community_aggregates_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO community_aggregates (community_id, published) + VALUES (NEW.id, NEW.published); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM community_aggregates + WHERE community_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create or replace function community_aggregates_community() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into community_aggregates (community_id, published) values (NEW.id, NEW.published); - ELSIF (TG_OP = 'DELETE') THEN - delete from community_aggregates where community_id = OLD.id; - END IF; - return null; -end $$; diff --git a/migrations/2021-02-25-112959_remove-categories/down.sql b/migrations/2021-02-25-112959_remove-categories/down.sql index 35386f795..61d8c8d57 100644 --- a/migrations/2021-02-25-112959_remove-categories/down.sql +++ b/migrations/2021-02-25-112959_remove-categories/down.sql @@ -1,34 +1,36 @@ -create table category ( - id serial primary key, - name varchar(100) not null unique +CREATE TABLE category ( + id serial PRIMARY KEY, + name varchar(100) NOT NULL UNIQUE ); -insert into category (name) values -('Discussion'), -('Humor/Memes'), -('Gaming'), -('Movies'), -('TV'), -('Music'), -('Literature'), -('Comics'), -('Photography'), -('Art'), -('Learning'), -('DIY'), -('Lifestyle'), -('News'), -('Politics'), -('Society'), -('Gender/Identity/Sexuality'), -('Race/Colonisation'), -('Religion'), -('Science/Technology'), -('Programming/Software'), -('Health/Sports/Fitness'), -('Porn'), -('Places'), -('Meta'), -('Other'); +INSERT INTO category (name) + VALUES ('Discussion'), + ('Humor/Memes'), + ('Gaming'), + ('Movies'), + ('TV'), + ('Music'), + ('Literature'), + ('Comics'), + ('Photography'), + ('Art'), + ('Learning'), + ('DIY'), + ('Lifestyle'), + ('News'), + ('Politics'), + ('Society'), + ('Gender/Identity/Sexuality'), + ('Race/Colonisation'), + ('Religion'), + ('Science/Technology'), + ('Programming/Software'), + ('Health/Sports/Fitness'), + ('Porn'), + ('Places'), + ('Meta'), + ('Other'); + +ALTER TABLE community + ADD category_id int REFERENCES category ON UPDATE CASCADE ON DELETE CASCADE NOT NULL DEFAULT 1; -ALTER TABLE community ADD category_id int references category on update cascade on delete cascade not null default 1; \ No newline at end of file diff --git a/migrations/2021-02-25-112959_remove-categories/up.sql b/migrations/2021-02-25-112959_remove-categories/up.sql index ebe83e541..6b39bfe00 100644 --- a/migrations/2021-02-25-112959_remove-categories/up.sql +++ b/migrations/2021-02-25-112959_remove-categories/up.sql @@ -1,2 +1,5 @@ -ALTER TABLE community DROP COLUMN category_id; +ALTER TABLE community + DROP COLUMN category_id; + DROP TABLE category; + diff --git a/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql b/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql index 7195601c9..0a9e8e2db 100644 --- a/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql +++ b/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql @@ -1,4 +1,5 @@ -- This is a clean-up migration that cannot be undone, -- but Diesel requires a non-empty script so run a no-op. -SELECT 1; +SELECT + 1; diff --git a/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql b/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql index 24e2d16b8..5e0916451 100644 --- a/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql +++ b/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql @@ -1 +1,7 @@ -UPDATE post SET url = NULL where url = ''; +UPDATE + post +SET + url = NULL +WHERE + url = ''; + diff --git a/migrations/2021-03-04-040229_clean_icon_urls/down.sql b/migrations/2021-03-04-040229_clean_icon_urls/down.sql index f866b155c..0a9e8e2db 100644 --- a/migrations/2021-03-04-040229_clean_icon_urls/down.sql +++ b/migrations/2021-03-04-040229_clean_icon_urls/down.sql @@ -1,3 +1,5 @@ -- This is a clean-up migration that cannot be undone, -- but Diesel requires a non-empty script so run a no-op. -SELECT 1; +SELECT + 1; + diff --git a/migrations/2021-03-04-040229_clean_icon_urls/up.sql b/migrations/2021-03-04-040229_clean_icon_urls/up.sql index 8b22b33fc..9fe28e8d4 100644 --- a/migrations/2021-03-04-040229_clean_icon_urls/up.sql +++ b/migrations/2021-03-04-040229_clean_icon_urls/up.sql @@ -1,5 +1,29 @@ -- If these are not urls, it will crash the server -update user_ set avatar = NULL where avatar not like 'http%'; -update user_ set banner = NULL where banner not like 'http%'; -update community set icon = NULL where icon not like 'http%'; -update community set banner = NULL where banner not like 'http%'; +UPDATE + user_ +SET + avatar = NULL +WHERE + avatar NOT LIKE 'http%'; + +UPDATE + user_ +SET + banner = NULL +WHERE + banner NOT LIKE 'http%'; + +UPDATE + community +SET + icon = NULL +WHERE + icon NOT LIKE 'http%'; + +UPDATE + community +SET + banner = NULL +WHERE + banner NOT LIKE 'http%'; + diff --git a/migrations/2021-03-09-171136_split_user_table_2/down.sql b/migrations/2021-03-09-171136_split_user_table_2/down.sql index e1d55a205..cba90ac49 100644 --- a/migrations/2021-03-09-171136_split_user_table_2/down.sql +++ b/migrations/2021-03-09-171136_split_user_table_2/down.sql @@ -1,359 +1,503 @@ -- post_saved -alter table post_saved rename column person_id to user_id; -alter table post_saved rename constraint post_saved_post_id_person_id_key to post_saved_post_id_user_id_key; -alter table post_saved rename constraint post_saved_person_id_fkey to post_saved_user_id_fkey; +ALTER TABLE post_saved RENAME COLUMN person_id TO user_id; + +ALTER TABLE post_saved RENAME CONSTRAINT post_saved_post_id_person_id_key TO post_saved_post_id_user_id_key; + +ALTER TABLE post_saved RENAME CONSTRAINT post_saved_person_id_fkey TO post_saved_user_id_fkey; -- post_read -alter table post_read rename column person_id to user_id; -alter table post_read rename constraint post_read_post_id_person_id_key to post_read_post_id_user_id_key; -alter table post_read rename constraint post_read_person_id_fkey to post_read_user_id_fkey; +ALTER TABLE post_read RENAME COLUMN person_id TO user_id; + +ALTER TABLE post_read RENAME CONSTRAINT post_read_post_id_person_id_key TO post_read_post_id_user_id_key; + +ALTER TABLE post_read RENAME CONSTRAINT post_read_person_id_fkey TO post_read_user_id_fkey; -- post_like -alter table post_like rename column person_id to user_id; -alter index idx_post_like_person rename to idx_post_like_user; -alter table post_like rename constraint post_like_post_id_person_id_key to post_like_post_id_user_id_key; -alter table post_like rename constraint post_like_person_id_fkey to post_like_user_id_fkey; +ALTER TABLE post_like RENAME COLUMN person_id TO user_id; + +ALTER INDEX idx_post_like_person RENAME TO idx_post_like_user; + +ALTER TABLE post_like RENAME CONSTRAINT post_like_post_id_person_id_key TO post_like_post_id_user_id_key; + +ALTER TABLE post_like RENAME CONSTRAINT post_like_person_id_fkey TO post_like_user_id_fkey; -- password_reset_request -delete from password_reset_request; -alter table password_reset_request drop column local_user_id; -alter table password_reset_request add column user_id integer not null references person(id) on update cascade on delete cascade; +DELETE FROM password_reset_request; + +ALTER TABLE password_reset_request + DROP COLUMN local_user_id; + +ALTER TABLE password_reset_request + ADD COLUMN user_id integer NOT NULL REFERENCES person (id) ON UPDATE CASCADE ON DELETE CASCADE; -- mod_sticky_post -alter table mod_sticky_post rename column mod_person_id to mod_user_id; -alter table mod_sticky_post rename constraint mod_sticky_post_mod_person_id_fkey to mod_sticky_post_mod_user_id_fkey; +ALTER TABLE mod_sticky_post RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_sticky_post RENAME CONSTRAINT mod_sticky_post_mod_person_id_fkey TO mod_sticky_post_mod_user_id_fkey; -- mod_remove_post -alter table mod_remove_post rename column mod_person_id to mod_user_id; -alter table mod_remove_post rename constraint mod_remove_post_mod_person_id_fkey to mod_remove_post_mod_user_id_fkey; +ALTER TABLE mod_remove_post RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_remove_post RENAME CONSTRAINT mod_remove_post_mod_person_id_fkey TO mod_remove_post_mod_user_id_fkey; -- mod_remove_community -alter table mod_remove_community rename column mod_person_id to mod_user_id; -alter table mod_remove_community rename constraint mod_remove_community_mod_person_id_fkey to mod_remove_community_mod_user_id_fkey; +ALTER TABLE mod_remove_community RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_remove_community RENAME CONSTRAINT mod_remove_community_mod_person_id_fkey TO mod_remove_community_mod_user_id_fkey; -- mod_remove_comment -alter table mod_remove_comment rename column mod_person_id to mod_user_id; -alter table mod_remove_comment rename constraint mod_remove_comment_mod_person_id_fkey to mod_remove_comment_mod_user_id_fkey; +ALTER TABLE mod_remove_comment RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_remove_comment RENAME CONSTRAINT mod_remove_comment_mod_person_id_fkey TO mod_remove_comment_mod_user_id_fkey; -- mod_lock_post -alter table mod_lock_post rename column mod_person_id to mod_user_id; -alter table mod_lock_post rename constraint mod_lock_post_mod_person_id_fkey to mod_lock_post_mod_user_id_fkey; +ALTER TABLE mod_lock_post RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_lock_post RENAME CONSTRAINT mod_lock_post_mod_person_id_fkey TO mod_lock_post_mod_user_id_fkey; -- mod_add_community -alter table mod_ban_from_community rename column mod_person_id to mod_user_id; -alter table mod_ban_from_community rename column other_person_id to other_user_id; -alter table mod_ban_from_community rename constraint mod_ban_from_community_mod_person_id_fkey to mod_ban_from_community_mod_user_id_fkey; -alter table mod_ban_from_community rename constraint mod_ban_from_community_other_person_id_fkey to mod_ban_from_community_other_user_id_fkey; +ALTER TABLE mod_ban_from_community RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_ban_from_community RENAME COLUMN other_person_id TO other_user_id; + +ALTER TABLE mod_ban_from_community RENAME CONSTRAINT mod_ban_from_community_mod_person_id_fkey TO mod_ban_from_community_mod_user_id_fkey; + +ALTER TABLE mod_ban_from_community RENAME CONSTRAINT mod_ban_from_community_other_person_id_fkey TO mod_ban_from_community_other_user_id_fkey; -- mod_ban -alter table mod_ban rename column mod_person_id to mod_user_id; -alter table mod_ban rename column other_person_id to other_user_id; -alter table mod_ban rename constraint mod_ban_mod_person_id_fkey to mod_ban_mod_user_id_fkey; -alter table mod_ban rename constraint mod_ban_other_person_id_fkey to mod_ban_other_user_id_fkey; +ALTER TABLE mod_ban RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_ban RENAME COLUMN other_person_id TO other_user_id; + +ALTER TABLE mod_ban RENAME CONSTRAINT mod_ban_mod_person_id_fkey TO mod_ban_mod_user_id_fkey; + +ALTER TABLE mod_ban RENAME CONSTRAINT mod_ban_other_person_id_fkey TO mod_ban_other_user_id_fkey; -- mod_add_community -alter table mod_add_community rename column mod_person_id to mod_user_id; -alter table mod_add_community rename column other_person_id to other_user_id; -alter table mod_add_community rename constraint mod_add_community_mod_person_id_fkey to mod_add_community_mod_user_id_fkey; -alter table mod_add_community rename constraint mod_add_community_other_person_id_fkey to mod_add_community_other_user_id_fkey; +ALTER TABLE mod_add_community RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_add_community RENAME COLUMN other_person_id TO other_user_id; + +ALTER TABLE mod_add_community RENAME CONSTRAINT mod_add_community_mod_person_id_fkey TO mod_add_community_mod_user_id_fkey; + +ALTER TABLE mod_add_community RENAME CONSTRAINT mod_add_community_other_person_id_fkey TO mod_add_community_other_user_id_fkey; -- mod_add -alter table mod_add rename column mod_person_id to mod_user_id; -alter table mod_add rename column other_person_id to other_user_id; -alter table mod_add rename constraint mod_add_mod_person_id_fkey to mod_add_mod_user_id_fkey; -alter table mod_add rename constraint mod_add_other_person_id_fkey to mod_add_other_user_id_fkey; +ALTER TABLE mod_add RENAME COLUMN mod_person_id TO mod_user_id; + +ALTER TABLE mod_add RENAME COLUMN other_person_id TO other_user_id; + +ALTER TABLE mod_add RENAME CONSTRAINT mod_add_mod_person_id_fkey TO mod_add_mod_user_id_fkey; + +ALTER TABLE mod_add RENAME CONSTRAINT mod_add_other_person_id_fkey TO mod_add_other_user_id_fkey; -- community_user_ban -alter table community_person_ban rename to community_user_ban; -alter sequence community_person_ban_id_seq rename to community_user_ban_id_seq; -alter table community_user_ban rename column person_id to user_id; -alter table community_user_ban rename constraint community_person_ban_pkey to community_user_ban_pkey; -alter table community_user_ban rename constraint community_person_ban_community_id_fkey to community_user_ban_community_id_fkey; -alter table community_user_ban rename constraint community_person_ban_community_id_person_id_key to community_user_ban_community_id_user_id_key; -alter table community_user_ban rename constraint community_person_ban_person_id_fkey to community_user_ban_user_id_fkey; +ALTER TABLE community_person_ban RENAME TO community_user_ban; + +ALTER SEQUENCE community_person_ban_id_seq + RENAME TO community_user_ban_id_seq; + +ALTER TABLE community_user_ban RENAME COLUMN person_id TO user_id; + +ALTER TABLE community_user_ban RENAME CONSTRAINT community_person_ban_pkey TO community_user_ban_pkey; + +ALTER TABLE community_user_ban RENAME CONSTRAINT community_person_ban_community_id_fkey TO community_user_ban_community_id_fkey; + +ALTER TABLE community_user_ban RENAME CONSTRAINT community_person_ban_community_id_person_id_key TO community_user_ban_community_id_user_id_key; + +ALTER TABLE community_user_ban RENAME CONSTRAINT community_person_ban_person_id_fkey TO community_user_ban_user_id_fkey; -- community_moderator -alter table community_moderator rename column person_id to user_id; -alter table community_moderator rename constraint community_moderator_community_id_person_id_key to community_moderator_community_id_user_id_key; -alter table community_moderator rename constraint community_moderator_person_id_fkey to community_moderator_user_id_fkey; +ALTER TABLE community_moderator RENAME COLUMN person_id TO user_id; + +ALTER TABLE community_moderator RENAME CONSTRAINT community_moderator_community_id_person_id_key TO community_moderator_community_id_user_id_key; + +ALTER TABLE community_moderator RENAME CONSTRAINT community_moderator_person_id_fkey TO community_moderator_user_id_fkey; -- community_follower -alter table community_follower rename column person_id to user_id; -alter table community_follower rename constraint community_follower_community_id_person_id_key to community_follower_community_id_user_id_key; -alter table community_follower rename constraint community_follower_person_id_fkey to community_follower_user_id_fkey; +ALTER TABLE community_follower RENAME COLUMN person_id TO user_id; + +ALTER TABLE community_follower RENAME CONSTRAINT community_follower_community_id_person_id_key TO community_follower_community_id_user_id_key; + +ALTER TABLE community_follower RENAME CONSTRAINT community_follower_person_id_fkey TO community_follower_user_id_fkey; -- comment_saved -alter table comment_saved rename column person_id to user_id; -alter table comment_saved rename constraint comment_saved_comment_id_person_id_key to comment_saved_comment_id_user_id_key; -alter table comment_saved rename constraint comment_saved_person_id_fkey to comment_saved_user_id_fkey; +ALTER TABLE comment_saved RENAME COLUMN person_id TO user_id; + +ALTER TABLE comment_saved RENAME CONSTRAINT comment_saved_comment_id_person_id_key TO comment_saved_comment_id_user_id_key; + +ALTER TABLE comment_saved RENAME CONSTRAINT comment_saved_person_id_fkey TO comment_saved_user_id_fkey; -- comment_like -alter table comment_like rename column person_id to user_id; -alter index idx_comment_like_person rename to idx_comment_like_user; -alter table comment_like rename constraint comment_like_comment_id_person_id_key to comment_like_comment_id_user_id_key; -alter table comment_like rename constraint comment_like_person_id_fkey to comment_like_user_id_fkey; +ALTER TABLE comment_like RENAME COLUMN person_id TO user_id; + +ALTER INDEX idx_comment_like_person RENAME TO idx_comment_like_user; + +ALTER TABLE comment_like RENAME CONSTRAINT comment_like_comment_id_person_id_key TO comment_like_comment_id_user_id_key; + +ALTER TABLE comment_like RENAME CONSTRAINT comment_like_person_id_fkey TO comment_like_user_id_fkey; -- user_ban -alter table person_ban rename to user_ban; -alter sequence person_ban_id_seq rename to user_ban_id_seq; -alter index person_ban_pkey rename to user_ban_pkey; -alter index person_ban_person_id_key rename to user_ban_user_id_key; -alter table user_ban rename column person_id to user_id; -alter table user_ban rename constraint person_ban_person_id_fkey to user_ban_user_id_fkey; +ALTER TABLE person_ban RENAME TO user_ban; + +ALTER SEQUENCE person_ban_id_seq + RENAME TO user_ban_id_seq; + +ALTER INDEX person_ban_pkey RENAME TO user_ban_pkey; + +ALTER INDEX person_ban_person_id_key RENAME TO user_ban_user_id_key; + +ALTER TABLE user_ban RENAME COLUMN person_id TO user_id; + +ALTER TABLE user_ban RENAME CONSTRAINT person_ban_person_id_fkey TO user_ban_user_id_fkey; -- user_mention -alter table person_mention rename to user_mention; -alter sequence person_mention_id_seq rename to user_mention_id_seq; -alter index person_mention_pkey rename to user_mention_pkey; -alter index person_mention_recipient_id_comment_id_key rename to user_mention_recipient_id_comment_id_key; -alter table user_mention rename constraint person_mention_comment_id_fkey to user_mention_comment_id_fkey; -alter table user_mention rename constraint person_mention_recipient_id_fkey to user_mention_recipient_id_fkey; +ALTER TABLE person_mention RENAME TO user_mention; + +ALTER SEQUENCE person_mention_id_seq + RENAME TO user_mention_id_seq; + +ALTER INDEX person_mention_pkey RENAME TO user_mention_pkey; + +ALTER INDEX person_mention_recipient_id_comment_id_key RENAME TO user_mention_recipient_id_comment_id_key; + +ALTER TABLE user_mention RENAME CONSTRAINT person_mention_comment_id_fkey TO user_mention_comment_id_fkey; + +ALTER TABLE user_mention RENAME CONSTRAINT person_mention_recipient_id_fkey TO user_mention_recipient_id_fkey; -- User aggregates table -alter table person_aggregates rename to user_aggregates; -alter sequence person_aggregates_id_seq rename to user_aggregates_id_seq; -alter table user_aggregates rename column person_id to user_id; +ALTER TABLE person_aggregates RENAME TO user_aggregates; + +ALTER SEQUENCE person_aggregates_id_seq + RENAME TO user_aggregates_id_seq; + +ALTER TABLE user_aggregates RENAME COLUMN person_id TO user_id; -- Indexes -alter index person_aggregates_pkey rename to user_aggregates_pkey; -alter index idx_person_aggregates_comment_score rename to idx_user_aggregates_comment_score; -alter index person_aggregates_person_id_key rename to user_aggregates_user_id_key; -alter table user_aggregates rename constraint person_aggregates_person_id_fkey to user_aggregates_user_id_fkey; +ALTER INDEX person_aggregates_pkey RENAME TO user_aggregates_pkey; + +ALTER INDEX idx_person_aggregates_comment_score RENAME TO idx_user_aggregates_comment_score; + +ALTER INDEX person_aggregates_person_id_key RENAME TO user_aggregates_user_id_key; + +ALTER TABLE user_aggregates RENAME CONSTRAINT person_aggregates_person_id_fkey TO user_aggregates_user_id_fkey; -- Redo the user_aggregates table -drop trigger person_aggregates_person on person; -drop trigger person_aggregates_post_count on post; -drop trigger person_aggregates_post_score on post_like; -drop trigger person_aggregates_comment_count on comment; -drop trigger person_aggregates_comment_score on comment_like; -drop function - person_aggregates_person, - person_aggregates_post_count, - person_aggregates_post_score, - person_aggregates_comment_count, - person_aggregates_comment_score; +DROP TRIGGER person_aggregates_person ON person; + +DROP TRIGGER person_aggregates_post_count ON post; + +DROP TRIGGER person_aggregates_post_score ON post_like; + +DROP TRIGGER person_aggregates_comment_count ON comment; + +DROP TRIGGER person_aggregates_comment_score ON comment_like; + +DROP FUNCTION person_aggregates_person, person_aggregates_post_count, person_aggregates_post_score, person_aggregates_comment_count, person_aggregates_comment_score; -- user_ table -- Drop views -drop view person_alias_1, person_alias_2; +DROP VIEW person_alias_1, person_alias_2; -- Rename indexes -alter index person__pkey rename to user__pkey; -alter index idx_person_actor_id rename to idx_user_actor_id; -alter index idx_person_inbox_url rename to idx_user_inbox_url; -alter index idx_person_lower_actor_id rename to idx_user_lower_actor_id; -alter index idx_person_published rename to idx_user_published; +ALTER INDEX person__pkey RENAME TO user__pkey; + +ALTER INDEX idx_person_actor_id RENAME TO idx_user_actor_id; + +ALTER INDEX idx_person_inbox_url RENAME TO idx_user_inbox_url; + +ALTER INDEX idx_person_lower_actor_id RENAME TO idx_user_lower_actor_id; + +ALTER INDEX idx_person_published RENAME TO idx_user_published; -- Rename triggers -alter trigger site_aggregates_person_delete on person rename to site_aggregates_user_delete; -alter trigger site_aggregates_person_insert on person rename to site_aggregates_user_insert; +ALTER TRIGGER site_aggregates_person_delete ON person RENAME TO site_aggregates_user_delete; + +ALTER TRIGGER site_aggregates_person_insert ON person RENAME TO site_aggregates_user_insert; -- Rename the trigger functions -alter function site_aggregates_person_delete() rename to site_aggregates_user_delete; -alter function site_aggregates_person_insert() rename to site_aggregates_user_insert; +ALTER FUNCTION site_aggregates_person_delete () RENAME TO site_aggregates_user_delete; + +ALTER FUNCTION site_aggregates_person_insert () RENAME TO site_aggregates_user_insert; -- Rename the table back to user_ -alter table person rename to user_; -alter sequence person_id_seq rename to user__id_seq; +ALTER TABLE person RENAME TO user_; + +ALTER SEQUENCE person_id_seq + RENAME TO user__id_seq; -- Add the columns back in -alter table user_ - add column password_encrypted text not null default 'changeme', - add column email text, - add column admin boolean default false not null, - add column show_nsfw boolean default false not null, - add column theme character varying(20) default 'darkly'::character varying not null, - add column default_sort_type smallint default 0 not null, - add column default_listing_type smallint default 1 not null, - add column lang character varying(20) default 'browser'::character varying not null, - add column show_avatars boolean default true not null, - add column send_notifications_to_email boolean default false not null, - add column matrix_user_id text; +ALTER TABLE user_ + ADD COLUMN password_encrypted text NOT NULL DEFAULT 'changeme', + ADD COLUMN email text, + ADD COLUMN admin boolean DEFAULT FALSE NOT NULL, + ADD COLUMN show_nsfw boolean DEFAULT FALSE NOT NULL, + ADD COLUMN theme character varying(20) DEFAULT 'darkly'::character varying NOT NULL, + ADD COLUMN default_sort_type smallint DEFAULT 0 NOT NULL, + ADD COLUMN default_listing_type smallint DEFAULT 1 NOT NULL, + ADD COLUMN lang character varying(20) DEFAULT 'browser'::character varying NOT NULL, + ADD COLUMN show_avatars boolean DEFAULT TRUE NOT NULL, + ADD COLUMN send_notifications_to_email boolean DEFAULT FALSE NOT NULL, + ADD COLUMN matrix_user_id text; -- Update the user_ table with the local_user data -update user_ u set - password_encrypted = lu.password_encrypted, - email = lu.email, - admin = lu.admin, - show_nsfw = lu.show_nsfw, - theme = lu.theme, - default_sort_type = lu.default_sort_type, - default_listing_type = lu.default_listing_type, - lang = lu.lang, - show_avatars = lu.show_avatars, - send_notifications_to_email = lu.send_notifications_to_email, - matrix_user_id = lu.matrix_user_id -from local_user lu -where lu.person_id = u.id; +UPDATE + user_ u +SET + password_encrypted = lu.password_encrypted, + email = lu.email, + admin = lu.admin, + show_nsfw = lu.show_nsfw, + theme = lu.theme, + default_sort_type = lu.default_sort_type, + default_listing_type = lu.default_listing_type, + lang = lu.lang, + show_avatars = lu.show_avatars, + send_notifications_to_email = lu.send_notifications_to_email, + matrix_user_id = lu.matrix_user_id +FROM + local_user lu +WHERE + lu.person_id = u.id; -create view user_alias_1 as select * from user_; -create view user_alias_2 as select * from user_; +CREATE VIEW user_alias_1 AS +SELECT + * +FROM + user_; -drop table local_user; +CREATE VIEW user_alias_2 AS +SELECT + * +FROM + user_; + +DROP TABLE local_user; -- Add the user_aggregates table triggers - -- initial user add -create function user_aggregates_user() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into user_aggregates (user_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from user_aggregates where user_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_user () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO user_aggregates (user_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM user_aggregates + WHERE user_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger user_aggregates_user -after insert or delete on user_ -for each row -execute procedure user_aggregates_user(); +CREATE TRIGGER user_aggregates_user + AFTER INSERT OR DELETE ON user_ + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_user (); -- post count -create function user_aggregates_post_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update user_aggregates - set post_count = post_count + 1 where user_id = NEW.creator_id; +CREATE FUNCTION user_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + user_aggregates + SET + post_count = post_count + 1 + WHERE + user_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates + SET + post_count = post_count - 1 + WHERE + user_id = OLD.creator_id; + -- If the post gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + user_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + user_ u + LEFT JOIN post p ON u.id = p.creator_id + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.user_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates - set post_count = post_count - 1 where user_id = OLD.creator_id; - - -- If the post gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update user_aggregates ua - set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from user_ u - left join post p on u.id = p.creator_id - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd - where ua.user_id = OLD.creator_id; - - END IF; - return null; -end $$; - -create trigger user_aggregates_post_count -after insert or delete on post -for each row -execute procedure user_aggregates_post_count(); +CREATE TRIGGER user_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_post_count (); -- post score -create function user_aggregates_post_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update user_aggregates ua - set post_score = post_score + NEW.score - from post p - where ua.user_id = p.creator_id and p.id = NEW.post_id; - - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates ua - set post_score = post_score - OLD.score - from post p - where ua.user_id = p.creator_id and p.id = OLD.post_id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_post_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + user_aggregates ua + SET + post_score = post_score + NEW.score + FROM + post p + WHERE + ua.user_id = p.creator_id + AND p.id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates ua + SET + post_score = post_score - OLD.score + FROM + post p + WHERE + ua.user_id = p.creator_id + AND p.id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -create trigger user_aggregates_post_score -after insert or delete on post_like -for each row -execute procedure user_aggregates_post_score(); +CREATE TRIGGER user_aggregates_post_score + AFTER INSERT OR DELETE ON post_like + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_post_score (); -- comment count -create function user_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update user_aggregates - set comment_count = comment_count + 1 where user_id = NEW.creator_id; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates - set comment_count = comment_count - 1 where user_id = OLD.creator_id; +CREATE FUNCTION user_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + user_aggregates + SET + comment_count = comment_count + 1 + WHERE + user_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates + SET + comment_count = comment_count - 1 + WHERE + user_id = OLD.creator_id; + -- If the comment gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + user_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + user_ u + LEFT JOIN comment c ON u.id = c.creator_id + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.user_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - -- If the comment gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update user_aggregates ua - set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from user_ u - left join comment c on u.id = c.creator_id - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd - where ua.user_id = OLD.creator_id; - END IF; - return null; -end $$; - -create trigger user_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure user_aggregates_comment_count(); +CREATE TRIGGER user_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_comment_count (); -- comment score -create function user_aggregates_comment_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update user_aggregates ua - set comment_score = comment_score + NEW.score - from comment c - where ua.user_id = c.creator_id and c.id = NEW.comment_id; - ELSIF (TG_OP = 'DELETE') THEN - update user_aggregates ua - set comment_score = comment_score - OLD.score - from comment c - where ua.user_id = c.creator_id and c.id = OLD.comment_id; - END IF; - return null; -end $$; +CREATE FUNCTION user_aggregates_comment_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + user_aggregates ua + SET + comment_score = comment_score + NEW.score + FROM + comment c + WHERE + ua.user_id = c.creator_id + AND c.id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + user_aggregates ua + SET + comment_score = comment_score - OLD.score + FROM + comment c + WHERE + ua.user_id = c.creator_id + AND c.id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; -create trigger user_aggregates_comment_score -after insert or delete on comment_like -for each row -execute procedure user_aggregates_comment_score(); +CREATE TRIGGER user_aggregates_comment_score + AFTER INSERT OR DELETE ON comment_like + FOR EACH ROW + EXECUTE PROCEDURE user_aggregates_comment_score (); -- redo site aggregates trigger -create or replace function site_aggregates_activity(i text) returns integer - language plpgsql - as $$ -declare - count_ integer; -begin - select count(*) - into count_ - from ( - select c.creator_id from comment c - inner join user_ u on c.creator_id = u.id - where c.published > ('now'::timestamp - i::interval) - and u.local = true - union - select p.creator_id from post p - inner join user_ u on p.creator_id = u.id - where p.published > ('now'::timestamp - i::interval) - and u.local = true - ) a; - return count_; -end; +CREATE OR REPLACE FUNCTION site_aggregates_activity (i text) + RETURNS integer + LANGUAGE plpgsql + AS $$ +DECLARE + count_ integer; +BEGIN + SELECT + count(*) INTO count_ + FROM ( + SELECT + c.creator_id + FROM + comment c + INNER JOIN user_ u ON c.creator_id = u.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + UNION + SELECT + p.creator_id + FROM + post p + INNER JOIN user_ u ON p.creator_id = u.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND u.local = TRUE) a; + RETURN count_; +END; $$; + diff --git a/migrations/2021-03-09-171136_split_user_table_2/up.sql b/migrations/2021-03-09-171136_split_user_table_2/up.sql index db3547e5f..4eb020d46 100644 --- a/migrations/2021-03-09-171136_split_user_table_2/up.sql +++ b/migrations/2021-03-09-171136_split_user_table_2/up.sql @@ -1,391 +1,519 @@ -- Person -- Drop the 2 views user_alias_1, user_alias_2 -drop view user_alias_1, user_alias_2; +DROP VIEW user_alias_1, user_alias_2; -- rename the user_ table to person -alter table user_ rename to person; -alter sequence user__id_seq rename to person_id_seq; +ALTER TABLE user_ RENAME TO person; + +ALTER SEQUENCE user__id_seq + RENAME TO person_id_seq; -- create a new table local_user -create table local_user ( - id serial primary key, - person_id int references person on update cascade on delete cascade not null, - password_encrypted text not null, - email text unique, - admin boolean default false not null, - show_nsfw boolean default false not null, - theme character varying(20) default 'darkly'::character varying not null, - default_sort_type smallint default 0 not null, - default_listing_type smallint default 1 not null, - lang character varying(20) default 'browser'::character varying not null, - show_avatars boolean default true not null, - send_notifications_to_email boolean default false not null, - matrix_user_id text, - unique (person_id) +CREATE TABLE local_user ( + id serial PRIMARY KEY, + person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + password_encrypted text NOT NULL, + email text UNIQUE, + admin boolean DEFAULT FALSE NOT NULL, + show_nsfw boolean DEFAULT FALSE NOT NULL, + theme character varying(20) DEFAULT 'darkly' ::character varying NOT NULL, + default_sort_type smallint DEFAULT 0 NOT NULL, + default_listing_type smallint DEFAULT 1 NOT NULL, + lang character varying(20) DEFAULT 'browser' ::character varying NOT NULL, + show_avatars boolean DEFAULT TRUE NOT NULL, + send_notifications_to_email boolean DEFAULT FALSE NOT NULL, + matrix_user_id text, + UNIQUE (person_id) ); -- Copy the local users over to the new table -insert into local_user -( - person_id, - password_encrypted, - email, - admin, - show_nsfw, - theme, - default_sort_type, - default_listing_type, - lang, - show_avatars, - send_notifications_to_email, - matrix_user_id -) -select - id, - password_encrypted, - email, - admin, - show_nsfw, - theme, - default_sort_type, - default_listing_type, - lang, - show_avatars, - send_notifications_to_email, - matrix_user_id -from person -where local = true; +INSERT INTO local_user (person_id, password_encrypted, email, admin, show_nsfw, theme, default_sort_type, default_listing_type, lang, show_avatars, send_notifications_to_email, matrix_user_id) +SELECT + id, + password_encrypted, + email, + admin, + show_nsfw, + theme, + default_sort_type, + default_listing_type, + lang, + show_avatars, + send_notifications_to_email, + matrix_user_id +FROM + person +WHERE + local = TRUE; -- Drop those columns from person -alter table person - drop column password_encrypted, - drop column email, - drop column admin, - drop column show_nsfw, - drop column theme, - drop column default_sort_type, - drop column default_listing_type, - drop column lang, - drop column show_avatars, - drop column send_notifications_to_email, - drop column matrix_user_id; +ALTER TABLE person + DROP COLUMN password_encrypted, + DROP COLUMN email, + DROP COLUMN admin, + DROP COLUMN show_nsfw, + DROP COLUMN theme, + DROP COLUMN default_sort_type, + DROP COLUMN default_listing_type, + DROP COLUMN lang, + DROP COLUMN show_avatars, + DROP COLUMN send_notifications_to_email, + DROP COLUMN matrix_user_id; -- Rename indexes -alter index user__pkey rename to person__pkey; -alter index idx_user_actor_id rename to idx_person_actor_id; -alter index idx_user_inbox_url rename to idx_person_inbox_url; -alter index idx_user_lower_actor_id rename to idx_person_lower_actor_id; -alter index idx_user_published rename to idx_person_published; +ALTER INDEX user__pkey RENAME TO person__pkey; + +ALTER INDEX idx_user_actor_id RENAME TO idx_person_actor_id; + +ALTER INDEX idx_user_inbox_url RENAME TO idx_person_inbox_url; + +ALTER INDEX idx_user_lower_actor_id RENAME TO idx_person_lower_actor_id; + +ALTER INDEX idx_user_published RENAME TO idx_person_published; -- Rename triggers -alter trigger site_aggregates_user_delete on person rename to site_aggregates_person_delete; -alter trigger site_aggregates_user_insert on person rename to site_aggregates_person_insert; +ALTER TRIGGER site_aggregates_user_delete ON person RENAME TO site_aggregates_person_delete; + +ALTER TRIGGER site_aggregates_user_insert ON person RENAME TO site_aggregates_person_insert; -- Rename the trigger functions -alter function site_aggregates_user_delete() rename to site_aggregates_person_delete; -alter function site_aggregates_user_insert() rename to site_aggregates_person_insert; +ALTER FUNCTION site_aggregates_user_delete () RENAME TO site_aggregates_person_delete; + +ALTER FUNCTION site_aggregates_user_insert () RENAME TO site_aggregates_person_insert; -- Create views -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; -- Redo user aggregates into person_aggregates -alter table user_aggregates rename to person_aggregates; -alter sequence user_aggregates_id_seq rename to person_aggregates_id_seq; -alter table person_aggregates rename column user_id to person_id; +ALTER TABLE user_aggregates RENAME TO person_aggregates; + +ALTER SEQUENCE user_aggregates_id_seq + RENAME TO person_aggregates_id_seq; + +ALTER TABLE person_aggregates RENAME COLUMN user_id TO person_id; -- index -alter index user_aggregates_pkey rename to person_aggregates_pkey; -alter index idx_user_aggregates_comment_score rename to idx_person_aggregates_comment_score; -alter index user_aggregates_user_id_key rename to person_aggregates_person_id_key; -alter table person_aggregates rename constraint user_aggregates_user_id_fkey to person_aggregates_person_id_fkey; +ALTER INDEX user_aggregates_pkey RENAME TO person_aggregates_pkey; +ALTER INDEX idx_user_aggregates_comment_score RENAME TO idx_person_aggregates_comment_score; + +ALTER INDEX user_aggregates_user_id_key RENAME TO person_aggregates_person_id_key; + +ALTER TABLE person_aggregates RENAME CONSTRAINT user_aggregates_user_id_fkey TO person_aggregates_person_id_fkey; -- Drop all the old triggers and functions -drop trigger user_aggregates_user on person; -drop trigger user_aggregates_post_count on post; -drop trigger user_aggregates_post_score on post_like; -drop trigger user_aggregates_comment_count on comment; -drop trigger user_aggregates_comment_score on comment_like; -drop function - user_aggregates_user, - user_aggregates_post_count, - user_aggregates_post_score, - user_aggregates_comment_count, - user_aggregates_comment_score; +DROP TRIGGER user_aggregates_user ON person; + +DROP TRIGGER user_aggregates_post_count ON post; + +DROP TRIGGER user_aggregates_post_score ON post_like; + +DROP TRIGGER user_aggregates_comment_count ON comment; + +DROP TRIGGER user_aggregates_comment_score ON comment_like; + +DROP FUNCTION user_aggregates_user, user_aggregates_post_count, user_aggregates_post_score, user_aggregates_comment_count, user_aggregates_comment_score; -- initial user add -create function person_aggregates_person() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into person_aggregates (person_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from person_aggregates where person_id = OLD.id; - END IF; - return null; -end $$; +CREATE FUNCTION person_aggregates_person () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO person_aggregates (person_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM person_aggregates + WHERE person_id = OLD.id; + END IF; + RETURN NULL; +END +$$; -create trigger person_aggregates_person -after insert or delete on person -for each row -execute procedure person_aggregates_person(); +CREATE TRIGGER person_aggregates_person + AFTER INSERT OR DELETE ON person + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_person (); -- post count -create function person_aggregates_post_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update person_aggregates - set post_count = post_count + 1 where person_id = NEW.creator_id; +CREATE FUNCTION person_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + person_aggregates + SET + post_count = post_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates + SET + post_count = post_count - 1 + WHERE + person_id = OLD.creator_id; + -- If the post gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + person_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + person u + LEFT JOIN post p ON u.id = p.creator_id + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.person_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - ELSIF (TG_OP = 'DELETE') THEN - update person_aggregates - set post_count = post_count - 1 where person_id = OLD.creator_id; - - -- If the post gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update person_aggregates ua - set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from person u - left join post p on u.id = p.creator_id - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd - where ua.person_id = OLD.creator_id; - - END IF; - return null; -end $$; - -create trigger person_aggregates_post_count -after insert or delete on post -for each row -execute procedure person_aggregates_post_count(); +CREATE TRIGGER person_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_post_count (); -- post score -create function person_aggregates_post_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update person_aggregates ua - set post_score = post_score + NEW.score - from post p - where ua.person_id = p.creator_id and p.id = NEW.post_id; - - ELSIF (TG_OP = 'DELETE') THEN - update person_aggregates ua - set post_score = post_score - OLD.score - from post p - where ua.person_id = p.creator_id and p.id = OLD.post_id; - END IF; - return null; -end $$; +CREATE FUNCTION person_aggregates_post_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + person_aggregates ua + SET + post_score = post_score + NEW.score + FROM + post p + WHERE + ua.person_id = p.creator_id + AND p.id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates ua + SET + post_score = post_score - OLD.score + FROM + post p + WHERE + ua.person_id = p.creator_id + AND p.id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -create trigger person_aggregates_post_score -after insert or delete on post_like -for each row -execute procedure person_aggregates_post_score(); +CREATE TRIGGER person_aggregates_post_score + AFTER INSERT OR DELETE ON post_like + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_post_score (); -- comment count -create function person_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update person_aggregates - set comment_count = comment_count + 1 where person_id = NEW.creator_id; - ELSIF (TG_OP = 'DELETE') THEN - update person_aggregates - set comment_count = comment_count - 1 where person_id = OLD.creator_id; +CREATE FUNCTION person_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + person_aggregates + SET + comment_count = comment_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates + SET + comment_count = comment_count - 1 + WHERE + person_id = OLD.creator_id; + -- If the comment gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + person_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + person u + LEFT JOIN comment c ON u.id = c.creator_id + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.person_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; - -- If the comment gets deleted, the score calculation trigger won't fire, - -- so you need to re-calculate - update person_aggregates ua - set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from person u - left join comment c on u.id = c.creator_id - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd - where ua.person_id = OLD.creator_id; - END IF; - return null; -end $$; - -create trigger person_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure person_aggregates_comment_count(); +CREATE TRIGGER person_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_comment_count (); -- comment score -create function person_aggregates_comment_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - -- Need to get the post creator, not the voter - update person_aggregates ua - set comment_score = comment_score + NEW.score - from comment c - where ua.person_id = c.creator_id and c.id = NEW.comment_id; - ELSIF (TG_OP = 'DELETE') THEN - update person_aggregates ua - set comment_score = comment_score - OLD.score - from comment c - where ua.person_id = c.creator_id and c.id = OLD.comment_id; - END IF; - return null; -end $$; +CREATE FUNCTION person_aggregates_comment_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + -- Need to get the post creator, not the voter + UPDATE + person_aggregates ua + SET + comment_score = comment_score + NEW.score + FROM + comment c + WHERE + ua.person_id = c.creator_id + AND c.id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates ua + SET + comment_score = comment_score - OLD.score + FROM + comment c + WHERE + ua.person_id = c.creator_id + AND c.id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; -create trigger person_aggregates_comment_score -after insert or delete on comment_like -for each row -execute procedure person_aggregates_comment_score(); +CREATE TRIGGER person_aggregates_comment_score + AFTER INSERT OR DELETE ON comment_like + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_comment_score (); -- person_mention -alter table user_mention rename to person_mention; -alter sequence user_mention_id_seq rename to person_mention_id_seq; -alter index user_mention_pkey rename to person_mention_pkey; -alter index user_mention_recipient_id_comment_id_key rename to person_mention_recipient_id_comment_id_key; -alter table person_mention rename constraint user_mention_comment_id_fkey to person_mention_comment_id_fkey; -alter table person_mention rename constraint user_mention_recipient_id_fkey to person_mention_recipient_id_fkey; +ALTER TABLE user_mention RENAME TO person_mention; + +ALTER SEQUENCE user_mention_id_seq + RENAME TO person_mention_id_seq; + +ALTER INDEX user_mention_pkey RENAME TO person_mention_pkey; + +ALTER INDEX user_mention_recipient_id_comment_id_key RENAME TO person_mention_recipient_id_comment_id_key; + +ALTER TABLE person_mention RENAME CONSTRAINT user_mention_comment_id_fkey TO person_mention_comment_id_fkey; + +ALTER TABLE person_mention RENAME CONSTRAINT user_mention_recipient_id_fkey TO person_mention_recipient_id_fkey; -- user_ban -alter table user_ban rename to person_ban; -alter sequence user_ban_id_seq rename to person_ban_id_seq; -alter index user_ban_pkey rename to person_ban_pkey; -alter index user_ban_user_id_key rename to person_ban_person_id_key; -alter table person_ban rename column user_id to person_id; -alter table person_ban rename constraint user_ban_user_id_fkey to person_ban_person_id_fkey; +ALTER TABLE user_ban RENAME TO person_ban; + +ALTER SEQUENCE user_ban_id_seq + RENAME TO person_ban_id_seq; + +ALTER INDEX user_ban_pkey RENAME TO person_ban_pkey; + +ALTER INDEX user_ban_user_id_key RENAME TO person_ban_person_id_key; + +ALTER TABLE person_ban RENAME COLUMN user_id TO person_id; + +ALTER TABLE person_ban RENAME CONSTRAINT user_ban_user_id_fkey TO person_ban_person_id_fkey; -- comment_like -alter table comment_like rename column user_id to person_id; -alter index idx_comment_like_user rename to idx_comment_like_person; -alter table comment_like rename constraint comment_like_comment_id_user_id_key to comment_like_comment_id_person_id_key; -alter table comment_like rename constraint comment_like_user_id_fkey to comment_like_person_id_fkey; +ALTER TABLE comment_like RENAME COLUMN user_id TO person_id; + +ALTER INDEX idx_comment_like_user RENAME TO idx_comment_like_person; + +ALTER TABLE comment_like RENAME CONSTRAINT comment_like_comment_id_user_id_key TO comment_like_comment_id_person_id_key; + +ALTER TABLE comment_like RENAME CONSTRAINT comment_like_user_id_fkey TO comment_like_person_id_fkey; -- comment_saved -alter table comment_saved rename column user_id to person_id; -alter table comment_saved rename constraint comment_saved_comment_id_user_id_key to comment_saved_comment_id_person_id_key; -alter table comment_saved rename constraint comment_saved_user_id_fkey to comment_saved_person_id_fkey; +ALTER TABLE comment_saved RENAME COLUMN user_id TO person_id; + +ALTER TABLE comment_saved RENAME CONSTRAINT comment_saved_comment_id_user_id_key TO comment_saved_comment_id_person_id_key; + +ALTER TABLE comment_saved RENAME CONSTRAINT comment_saved_user_id_fkey TO comment_saved_person_id_fkey; -- community_follower -alter table community_follower rename column user_id to person_id; -alter table community_follower rename constraint community_follower_community_id_user_id_key to community_follower_community_id_person_id_key; -alter table community_follower rename constraint community_follower_user_id_fkey to community_follower_person_id_fkey; +ALTER TABLE community_follower RENAME COLUMN user_id TO person_id; + +ALTER TABLE community_follower RENAME CONSTRAINT community_follower_community_id_user_id_key TO community_follower_community_id_person_id_key; + +ALTER TABLE community_follower RENAME CONSTRAINT community_follower_user_id_fkey TO community_follower_person_id_fkey; -- community_moderator -alter table community_moderator rename column user_id to person_id; -alter table community_moderator rename constraint community_moderator_community_id_user_id_key to community_moderator_community_id_person_id_key; -alter table community_moderator rename constraint community_moderator_user_id_fkey to community_moderator_person_id_fkey; +ALTER TABLE community_moderator RENAME COLUMN user_id TO person_id; + +ALTER TABLE community_moderator RENAME CONSTRAINT community_moderator_community_id_user_id_key TO community_moderator_community_id_person_id_key; + +ALTER TABLE community_moderator RENAME CONSTRAINT community_moderator_user_id_fkey TO community_moderator_person_id_fkey; -- community_user_ban -alter table community_user_ban rename to community_person_ban; -alter sequence community_user_ban_id_seq rename to community_person_ban_id_seq; -alter table community_person_ban rename column user_id to person_id; -alter table community_person_ban rename constraint community_user_ban_pkey to community_person_ban_pkey; -alter table community_person_ban rename constraint community_user_ban_community_id_fkey to community_person_ban_community_id_fkey; -alter table community_person_ban rename constraint community_user_ban_community_id_user_id_key to community_person_ban_community_id_person_id_key; -alter table community_person_ban rename constraint community_user_ban_user_id_fkey to community_person_ban_person_id_fkey; +ALTER TABLE community_user_ban RENAME TO community_person_ban; + +ALTER SEQUENCE community_user_ban_id_seq + RENAME TO community_person_ban_id_seq; + +ALTER TABLE community_person_ban RENAME COLUMN user_id TO person_id; + +ALTER TABLE community_person_ban RENAME CONSTRAINT community_user_ban_pkey TO community_person_ban_pkey; + +ALTER TABLE community_person_ban RENAME CONSTRAINT community_user_ban_community_id_fkey TO community_person_ban_community_id_fkey; + +ALTER TABLE community_person_ban RENAME CONSTRAINT community_user_ban_community_id_user_id_key TO community_person_ban_community_id_person_id_key; + +ALTER TABLE community_person_ban RENAME CONSTRAINT community_user_ban_user_id_fkey TO community_person_ban_person_id_fkey; -- mod_add -alter table mod_add rename column mod_user_id to mod_person_id; -alter table mod_add rename column other_user_id to other_person_id; -alter table mod_add rename constraint mod_add_mod_user_id_fkey to mod_add_mod_person_id_fkey; -alter table mod_add rename constraint mod_add_other_user_id_fkey to mod_add_other_person_id_fkey; +ALTER TABLE mod_add RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_add RENAME COLUMN other_user_id TO other_person_id; + +ALTER TABLE mod_add RENAME CONSTRAINT mod_add_mod_user_id_fkey TO mod_add_mod_person_id_fkey; + +ALTER TABLE mod_add RENAME CONSTRAINT mod_add_other_user_id_fkey TO mod_add_other_person_id_fkey; -- mod_add_community -alter table mod_add_community rename column mod_user_id to mod_person_id; -alter table mod_add_community rename column other_user_id to other_person_id; -alter table mod_add_community rename constraint mod_add_community_mod_user_id_fkey to mod_add_community_mod_person_id_fkey; -alter table mod_add_community rename constraint mod_add_community_other_user_id_fkey to mod_add_community_other_person_id_fkey; +ALTER TABLE mod_add_community RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_add_community RENAME COLUMN other_user_id TO other_person_id; + +ALTER TABLE mod_add_community RENAME CONSTRAINT mod_add_community_mod_user_id_fkey TO mod_add_community_mod_person_id_fkey; + +ALTER TABLE mod_add_community RENAME CONSTRAINT mod_add_community_other_user_id_fkey TO mod_add_community_other_person_id_fkey; -- mod_ban -alter table mod_ban rename column mod_user_id to mod_person_id; -alter table mod_ban rename column other_user_id to other_person_id; -alter table mod_ban rename constraint mod_ban_mod_user_id_fkey to mod_ban_mod_person_id_fkey; -alter table mod_ban rename constraint mod_ban_other_user_id_fkey to mod_ban_other_person_id_fkey; +ALTER TABLE mod_ban RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_ban RENAME COLUMN other_user_id TO other_person_id; + +ALTER TABLE mod_ban RENAME CONSTRAINT mod_ban_mod_user_id_fkey TO mod_ban_mod_person_id_fkey; + +ALTER TABLE mod_ban RENAME CONSTRAINT mod_ban_other_user_id_fkey TO mod_ban_other_person_id_fkey; -- mod_ban_community -alter table mod_ban_from_community rename column mod_user_id to mod_person_id; -alter table mod_ban_from_community rename column other_user_id to other_person_id; -alter table mod_ban_from_community rename constraint mod_ban_from_community_mod_user_id_fkey to mod_ban_from_community_mod_person_id_fkey; -alter table mod_ban_from_community rename constraint mod_ban_from_community_other_user_id_fkey to mod_ban_from_community_other_person_id_fkey; +ALTER TABLE mod_ban_from_community RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_ban_from_community RENAME COLUMN other_user_id TO other_person_id; + +ALTER TABLE mod_ban_from_community RENAME CONSTRAINT mod_ban_from_community_mod_user_id_fkey TO mod_ban_from_community_mod_person_id_fkey; + +ALTER TABLE mod_ban_from_community RENAME CONSTRAINT mod_ban_from_community_other_user_id_fkey TO mod_ban_from_community_other_person_id_fkey; -- mod_lock_post -alter table mod_lock_post rename column mod_user_id to mod_person_id; -alter table mod_lock_post rename constraint mod_lock_post_mod_user_id_fkey to mod_lock_post_mod_person_id_fkey; +ALTER TABLE mod_lock_post RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_lock_post RENAME CONSTRAINT mod_lock_post_mod_user_id_fkey TO mod_lock_post_mod_person_id_fkey; -- mod_remove_comment -alter table mod_remove_comment rename column mod_user_id to mod_person_id; -alter table mod_remove_comment rename constraint mod_remove_comment_mod_user_id_fkey to mod_remove_comment_mod_person_id_fkey; +ALTER TABLE mod_remove_comment RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_remove_comment RENAME CONSTRAINT mod_remove_comment_mod_user_id_fkey TO mod_remove_comment_mod_person_id_fkey; -- mod_remove_community -alter table mod_remove_community rename column mod_user_id to mod_person_id; -alter table mod_remove_community rename constraint mod_remove_community_mod_user_id_fkey to mod_remove_community_mod_person_id_fkey; +ALTER TABLE mod_remove_community RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_remove_community RENAME CONSTRAINT mod_remove_community_mod_user_id_fkey TO mod_remove_community_mod_person_id_fkey; -- mod_remove_post -alter table mod_remove_post rename column mod_user_id to mod_person_id; -alter table mod_remove_post rename constraint mod_remove_post_mod_user_id_fkey to mod_remove_post_mod_person_id_fkey; +ALTER TABLE mod_remove_post RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_remove_post RENAME CONSTRAINT mod_remove_post_mod_user_id_fkey TO mod_remove_post_mod_person_id_fkey; -- mod_sticky_post -alter table mod_sticky_post rename column mod_user_id to mod_person_id; -alter table mod_sticky_post rename constraint mod_sticky_post_mod_user_id_fkey to mod_sticky_post_mod_person_id_fkey; +ALTER TABLE mod_sticky_post RENAME COLUMN mod_user_id TO mod_person_id; + +ALTER TABLE mod_sticky_post RENAME CONSTRAINT mod_sticky_post_mod_user_id_fkey TO mod_sticky_post_mod_person_id_fkey; -- password_reset_request -delete from password_reset_request; -alter table password_reset_request drop column user_id; -alter table password_reset_request add column local_user_id integer not null references local_user(id) on update cascade on delete cascade; +DELETE FROM password_reset_request; + +ALTER TABLE password_reset_request + DROP COLUMN user_id; + +ALTER TABLE password_reset_request + ADD COLUMN local_user_id integer NOT NULL REFERENCES local_user (id) ON UPDATE CASCADE ON DELETE CASCADE; -- post_like -alter table post_like rename column user_id to person_id; -alter index idx_post_like_user rename to idx_post_like_person; -alter table post_like rename constraint post_like_post_id_user_id_key to post_like_post_id_person_id_key; -alter table post_like rename constraint post_like_user_id_fkey to post_like_person_id_fkey; +ALTER TABLE post_like RENAME COLUMN user_id TO person_id; + +ALTER INDEX idx_post_like_user RENAME TO idx_post_like_person; + +ALTER TABLE post_like RENAME CONSTRAINT post_like_post_id_user_id_key TO post_like_post_id_person_id_key; + +ALTER TABLE post_like RENAME CONSTRAINT post_like_user_id_fkey TO post_like_person_id_fkey; -- post_read -alter table post_read rename column user_id to person_id; -alter table post_read rename constraint post_read_post_id_user_id_key to post_read_post_id_person_id_key; -alter table post_read rename constraint post_read_user_id_fkey to post_read_person_id_fkey; +ALTER TABLE post_read RENAME COLUMN user_id TO person_id; + +ALTER TABLE post_read RENAME CONSTRAINT post_read_post_id_user_id_key TO post_read_post_id_person_id_key; + +ALTER TABLE post_read RENAME CONSTRAINT post_read_user_id_fkey TO post_read_person_id_fkey; -- post_saved -alter table post_saved rename column user_id to person_id; -alter table post_saved rename constraint post_saved_post_id_user_id_key to post_saved_post_id_person_id_key; -alter table post_saved rename constraint post_saved_user_id_fkey to post_saved_person_id_fkey; +ALTER TABLE post_saved RENAME COLUMN user_id TO person_id; + +ALTER TABLE post_saved RENAME CONSTRAINT post_saved_post_id_user_id_key TO post_saved_post_id_person_id_key; + +ALTER TABLE post_saved RENAME CONSTRAINT post_saved_user_id_fkey TO post_saved_person_id_fkey; -- redo site aggregates trigger -create or replace function site_aggregates_activity(i text) returns integer - language plpgsql - as $$ -declare - count_ integer; -begin - select count(*) - into count_ - from ( - select c.creator_id from comment c - inner join person u on c.creator_id = u.id - where c.published > ('now'::timestamp - i::interval) - and u.local = true - union - select p.creator_id from post p - inner join person u on p.creator_id = u.id - where p.published > ('now'::timestamp - i::interval) - and u.local = true - ) a; - return count_; -end; +CREATE OR REPLACE FUNCTION site_aggregates_activity (i text) + RETURNS integer + LANGUAGE plpgsql + AS $$ +DECLARE + count_ integer; +BEGIN + SELECT + count(*) INTO count_ + FROM ( + SELECT + c.creator_id + FROM + comment c + INNER JOIN person u ON c.creator_id = u.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + UNION + SELECT + p.creator_id + FROM + post p + INNER JOIN person u ON p.creator_id = u.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND u.local = TRUE) a; + RETURN count_; +END; $$; + diff --git a/migrations/2021-03-19-014144_add_col_local_user_validator_time/down.sql b/migrations/2021-03-19-014144_add_col_local_user_validator_time/down.sql index 657bfb3d4..d59419bfb 100644 --- a/migrations/2021-03-19-014144_add_col_local_user_validator_time/down.sql +++ b/migrations/2021-03-19-014144_add_col_local_user_validator_time/down.sql @@ -1 +1,3 @@ -alter table local_user drop column validator_time; +ALTER TABLE local_user + DROP COLUMN validator_time; + diff --git a/migrations/2021-03-19-014144_add_col_local_user_validator_time/up.sql b/migrations/2021-03-19-014144_add_col_local_user_validator_time/up.sql index 4fbb5eb91..3f3ac07af 100644 --- a/migrations/2021-03-19-014144_add_col_local_user_validator_time/up.sql +++ b/migrations/2021-03-19-014144_add_col_local_user_validator_time/up.sql @@ -1 +1,3 @@ -alter table local_user add column validator_time timestamp not null default now(); +ALTER TABLE local_user + ADD COLUMN validator_time timestamp NOT NULL DEFAULT now(); + diff --git a/migrations/2021-03-20-185321_move_matrix_id_to_person/down.sql b/migrations/2021-03-20-185321_move_matrix_id_to_person/down.sql index 990d8fe97..548dc9a0e 100644 --- a/migrations/2021-03-20-185321_move_matrix_id_to_person/down.sql +++ b/migrations/2021-03-20-185321_move_matrix_id_to_person/down.sql @@ -1,17 +1,37 @@ -alter table local_user add column matrix_user_id text; -alter table local_user add column admin boolean default false not null; +ALTER TABLE local_user + ADD COLUMN matrix_user_id text; -update local_user lu -set - matrix_user_id = p.matrix_user_id, - admin = p.admin -from person p -where p.id = lu.person_id; +ALTER TABLE local_user + ADD COLUMN admin boolean DEFAULT FALSE NOT NULL; -drop view person_alias_1, person_alias_2; -alter table person drop column matrix_user_id; -alter table person drop column admin; +UPDATE + local_user lu +SET + matrix_user_id = p.matrix_user_id, + admin = p.admin +FROM + person p +WHERE + p.id = lu.person_id; + +DROP VIEW person_alias_1, person_alias_2; + +ALTER TABLE person + DROP COLUMN matrix_user_id; + +ALTER TABLE person + DROP COLUMN admin; -- Regenerate the person_alias views -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + diff --git a/migrations/2021-03-20-185321_move_matrix_id_to_person/up.sql b/migrations/2021-03-20-185321_move_matrix_id_to_person/up.sql index d9ba3dd9c..7c7c1fb4f 100644 --- a/migrations/2021-03-20-185321_move_matrix_id_to_person/up.sql +++ b/migrations/2021-03-20-185321_move_matrix_id_to_person/up.sql @@ -1,17 +1,37 @@ -alter table person add column matrix_user_id text; -alter table person add column admin boolean default false not null; +ALTER TABLE person + ADD COLUMN matrix_user_id text; -update person p -set - matrix_user_id = lu.matrix_user_id, - admin = lu.admin -from local_user lu -where p.id = lu.person_id; +ALTER TABLE person + ADD COLUMN admin boolean DEFAULT FALSE NOT NULL; -alter table local_user drop column matrix_user_id; -alter table local_user drop column admin; +UPDATE + person p +SET + matrix_user_id = lu.matrix_user_id, + admin = lu.admin +FROM + local_user lu +WHERE + p.id = lu.person_id; + +ALTER TABLE local_user + DROP COLUMN matrix_user_id; + +ALTER TABLE local_user + DROP COLUMN admin; -- Regenerate the person_alias views -drop view person_alias_1, person_alias_2; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +DROP VIEW person_alias_1, person_alias_2; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + diff --git a/migrations/2021-03-31-103917_add_show_score_setting/down.sql b/migrations/2021-03-31-103917_add_show_score_setting/down.sql index 9d35b5638..20fc01c4e 100644 --- a/migrations/2021-03-31-103917_add_show_score_setting/down.sql +++ b/migrations/2021-03-31-103917_add_show_score_setting/down.sql @@ -1 +1,3 @@ -alter table local_user drop column show_scores; +ALTER TABLE local_user + DROP COLUMN show_scores; + diff --git a/migrations/2021-03-31-103917_add_show_score_setting/up.sql b/migrations/2021-03-31-103917_add_show_score_setting/up.sql index 7960886a3..94ca9bbd2 100644 --- a/migrations/2021-03-31-103917_add_show_score_setting/up.sql +++ b/migrations/2021-03-31-103917_add_show_score_setting/up.sql @@ -1 +1,3 @@ -alter table local_user add column show_scores boolean default true not null; +ALTER TABLE local_user + ADD COLUMN show_scores boolean DEFAULT TRUE NOT NULL; + diff --git a/migrations/2021-03-31-105915_add_bot_account/down.sql b/migrations/2021-03-31-105915_add_bot_account/down.sql index 4f407ce86..d4d0ef047 100644 --- a/migrations/2021-03-31-105915_add_bot_account/down.sql +++ b/migrations/2021-03-31-105915_add_bot_account/down.sql @@ -1,6 +1,20 @@ -drop view person_alias_1, person_alias_2; -alter table person drop column bot_account; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +DROP VIEW person_alias_1, person_alias_2; + +ALTER TABLE person + DROP COLUMN bot_account; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + +ALTER TABLE local_user + DROP COLUMN show_bot_accounts; -alter table local_user drop column show_bot_accounts; diff --git a/migrations/2021-03-31-105915_add_bot_account/up.sql b/migrations/2021-03-31-105915_add_bot_account/up.sql index a1e207a1d..7fc62811a 100644 --- a/migrations/2021-03-31-105915_add_bot_account/up.sql +++ b/migrations/2021-03-31-105915_add_bot_account/up.sql @@ -1,8 +1,22 @@ -- Add the bot_account column to the person table -drop view person_alias_1, person_alias_2; -alter table person add column bot_account boolean not null default false; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +DROP VIEW person_alias_1, person_alias_2; + +ALTER TABLE person + ADD COLUMN bot_account boolean NOT NULL DEFAULT FALSE; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; -- Add the show_bot_accounts to the local user table as a setting -alter table local_user add column show_bot_accounts boolean not null default true; +ALTER TABLE local_user + ADD COLUMN show_bot_accounts boolean NOT NULL DEFAULT TRUE; + diff --git a/migrations/2021-03-31-144349_add_site_short_description/down.sql b/migrations/2021-03-31-144349_add_site_short_description/down.sql index 0035ee770..a1eab23de 100644 --- a/migrations/2021-03-31-144349_add_site_short_description/down.sql +++ b/migrations/2021-03-31-144349_add_site_short_description/down.sql @@ -1,2 +1,5 @@ -alter table site drop column description; -alter table site rename column sidebar to description; +ALTER TABLE site + DROP COLUMN description; + +ALTER TABLE site RENAME COLUMN sidebar TO description; + diff --git a/migrations/2021-03-31-144349_add_site_short_description/up.sql b/migrations/2021-03-31-144349_add_site_short_description/up.sql index 09dc36a7d..14d63c880 100644 --- a/migrations/2021-03-31-144349_add_site_short_description/up.sql +++ b/migrations/2021-03-31-144349_add_site_short_description/up.sql @@ -1,5 +1,7 @@ -- Renaming description to sidebar -alter table site rename column description to sidebar; +ALTER TABLE site RENAME COLUMN description TO sidebar; -- Adding a short description column -alter table site add column description varchar(150); +ALTER TABLE site + ADD COLUMN description varchar(150); + diff --git a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql index 844c02d38..112dc5b4c 100644 --- a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql +++ b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql @@ -1,6 +1,17 @@ -alter table person rename display_name to preferred_username; +ALTER TABLE person RENAME display_name TO preferred_username; -- Regenerate the person_alias views -drop view person_alias_1, person_alias_2; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +DROP VIEW person_alias_1, person_alias_2; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + diff --git a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql index f4b9729c1..17110d329 100644 --- a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql +++ b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql @@ -1,6 +1,17 @@ -alter table person rename preferred_username to display_name; +ALTER TABLE person RENAME preferred_username TO display_name; -- Regenerate the person_alias views -drop view person_alias_1, person_alias_2; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +DROP VIEW person_alias_1, person_alias_2; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + diff --git a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql index 9748bc17f..ba8cf93ec 100644 --- a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql +++ b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql @@ -1 +1,2 @@ -drop index idx_community_aggregates_users_active_month; +DROP INDEX idx_community_aggregates_users_active_month; + diff --git a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql index 4ae90e0ab..576912507 100644 --- a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql +++ b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql @@ -1,2 +1,2 @@ -create index idx_community_aggregates_users_active_month on community_aggregates (users_active_month desc); +CREATE INDEX idx_community_aggregates_users_active_month ON community_aggregates (users_active_month DESC); diff --git a/migrations/2021-04-02-021422_remove_community_creator/down.sql b/migrations/2021-04-02-021422_remove_community_creator/down.sql index d015f252b..dc94ae361 100644 --- a/migrations/2021-04-02-021422_remove_community_creator/down.sql +++ b/migrations/2021-04-02-021422_remove_community_creator/down.sql @@ -1,24 +1,26 @@ - -- Add the column back -alter table community add column creator_id int references person on update cascade on delete cascade; +ALTER TABLE community + ADD COLUMN creator_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE; -- Recreate the index -create index idx_community_creator on community (creator_id); +CREATE INDEX idx_community_creator ON community (creator_id); -- Add the data, selecting the highest mod -update community -set creator_id = sub.person_id -from ( - select - cm.community_id, - cm.person_id - from - community_moderator cm - limit 1 -) as sub -where id = sub.community_id; +UPDATE + community +SET + creator_id = sub.person_id +FROM ( + SELECT + cm.community_id, + cm.person_id + FROM + community_moderator cm + LIMIT 1) AS sub +WHERE + id = sub.community_id; -- Set to not null -alter table community alter column creator_id set not null; - +ALTER TABLE community + ALTER COLUMN creator_id SET NOT NULL; diff --git a/migrations/2021-04-02-021422_remove_community_creator/up.sql b/migrations/2021-04-02-021422_remove_community_creator/up.sql index c3415c6ab..cd41f86c5 100644 --- a/migrations/2021-04-02-021422_remove_community_creator/up.sql +++ b/migrations/2021-04-02-021422_remove_community_creator/up.sql @@ -1,2 +1,4 @@ -- Drop the column -alter table community drop column creator_id; +ALTER TABLE community + DROP COLUMN creator_id; + diff --git a/migrations/2021-04-20-155001_limit-admins-create-community/down.sql b/migrations/2021-04-20-155001_limit-admins-create-community/down.sql index a04036f4f..a1475fbd7 100644 --- a/migrations/2021-04-20-155001_limit-admins-create-community/down.sql +++ b/migrations/2021-04-20-155001_limit-admins-create-community/down.sql @@ -1 +1,3 @@ -ALTER TABLE site DROP COLUMN community_creation_admin_only; +ALTER TABLE site + DROP COLUMN community_creation_admin_only; + diff --git a/migrations/2021-04-20-155001_limit-admins-create-community/up.sql b/migrations/2021-04-20-155001_limit-admins-create-community/up.sql index f302f88af..44d5be699 100644 --- a/migrations/2021-04-20-155001_limit-admins-create-community/up.sql +++ b/migrations/2021-04-20-155001_limit-admins-create-community/up.sql @@ -1 +1,3 @@ -ALTER TABLE site ADD COLUMN community_creation_admin_only bool NOT NULL DEFAULT false; +ALTER TABLE site + ADD COLUMN community_creation_admin_only bool NOT NULL DEFAULT FALSE; + diff --git a/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql b/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql index 2aa275147..040bbeb5c 100644 --- a/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql +++ b/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql @@ -1 +1,3 @@ -alter table local_user drop column show_read_posts; +ALTER TABLE local_user + DROP COLUMN show_read_posts; + diff --git a/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql b/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql index 74b5398c3..a5c26245b 100644 --- a/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql +++ b/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql @@ -1 +1,3 @@ -alter table local_user add column show_read_posts boolean default true not null; +ALTER TABLE local_user + ADD COLUMN show_read_posts boolean DEFAULT TRUE NOT NULL; + diff --git a/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/down.sql b/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/down.sql index 197c36ebc..60cf51064 100644 --- a/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/down.sql +++ b/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/down.sql @@ -1 +1,3 @@ -alter table local_user drop column show_new_post_notifs; +ALTER TABLE local_user + DROP COLUMN show_new_post_notifs; + diff --git a/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/up.sql b/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/up.sql index 7c6960b44..de5c6a729 100644 --- a/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/up.sql +++ b/migrations/2021-07-19-130929_add_show_new_post_notifs_setting/up.sql @@ -1 +1,3 @@ -alter table local_user add column show_new_post_notifs boolean default false not null; +ALTER TABLE local_user + ADD COLUMN show_new_post_notifs boolean DEFAULT FALSE NOT NULL; + diff --git a/migrations/2021-07-20-102033_actor_name_length/down.sql b/migrations/2021-07-20-102033_actor_name_length/down.sql index 76cec4c91..c8436ad89 100644 --- a/migrations/2021-07-20-102033_actor_name_length/down.sql +++ b/migrations/2021-07-20-102033_actor_name_length/down.sql @@ -1,10 +1,28 @@ DROP VIEW person_alias_1; + DROP VIEW person_alias_2; -ALTER TABLE community ALTER COLUMN name TYPE varchar(20); -ALTER TABLE community ALTER COLUMN title TYPE varchar(100); -ALTER TABLE person ALTER COLUMN name TYPE varchar(20); -ALTER TABLE person ALTER COLUMN display_name TYPE varchar(20); +ALTER TABLE community + ALTER COLUMN name TYPE varchar(20); + +ALTER TABLE community + ALTER COLUMN title TYPE varchar(100); + +ALTER TABLE person + ALTER COLUMN name TYPE varchar(20); + +ALTER TABLE person + ALTER COLUMN display_name TYPE varchar(20); + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; diff --git a/migrations/2021-07-20-102033_actor_name_length/up.sql b/migrations/2021-07-20-102033_actor_name_length/up.sql index 2e7bc9dfb..2db7c3b46 100644 --- a/migrations/2021-07-20-102033_actor_name_length/up.sql +++ b/migrations/2021-07-20-102033_actor_name_length/up.sql @@ -1,10 +1,28 @@ DROP VIEW person_alias_1; + DROP VIEW person_alias_2; -ALTER TABLE community ALTER COLUMN name TYPE varchar(255); -ALTER TABLE community ALTER COLUMN title TYPE varchar(255); -ALTER TABLE person ALTER COLUMN name TYPE varchar(255); -ALTER TABLE person ALTER COLUMN display_name TYPE varchar(255); +ALTER TABLE community + ALTER COLUMN name TYPE varchar(255); + +ALTER TABLE community + ALTER COLUMN title TYPE varchar(255); + +ALTER TABLE person + ALTER COLUMN name TYPE varchar(255); + +ALTER TABLE person + ALTER COLUMN display_name TYPE varchar(255); + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; diff --git a/migrations/2021-08-02-002342_comment_count_fixes/down.sql b/migrations/2021-08-02-002342_comment_count_fixes/down.sql index 3a895f70b..79578462f 100644 --- a/migrations/2021-08-02-002342_comment_count_fixes/down.sql +++ b/migrations/2021-08-02-002342_comment_count_fixes/down.sql @@ -1,28 +1,41 @@ -drop trigger post_aggregates_comment_set_deleted on comment; -drop function post_aggregates_comment_deleted; +DROP TRIGGER post_aggregates_comment_set_deleted ON comment; -create or replace function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1, - newest_comment_time = NEW.published - where pa.post_id = NEW.post_id; +DROP FUNCTION post_aggregates_comment_deleted; + +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1, + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time_necro = NEW.published + WHERE + pa.post_id = NEW.post_id + AND published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time_necro = NEW.published - where pa.post_id = NEW.post_id - and published > ('now'::timestamp - '2 days'::interval); - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; diff --git a/migrations/2021-08-02-002342_comment_count_fixes/up.sql b/migrations/2021-08-02-002342_comment_count_fixes/up.sql index b65f60089..81edf344b 100644 --- a/migrations/2021-08-02-002342_comment_count_fixes/up.sql +++ b/migrations/2021-08-02-002342_comment_count_fixes/up.sql @@ -1,61 +1,84 @@ -- Creating a new trigger for when comment.deleted is updated +CREATE OR REPLACE FUNCTION post_aggregates_comment_deleted () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF NEW.deleted = TRUE THEN + UPDATE + post_aggregates pa + SET + comments = comments - 1 + WHERE + pa.post_id = NEW.post_id; + ELSE + UPDATE + post_aggregates pa + SET + comments = comments + 1 + WHERE + pa.post_id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; -create or replace function post_aggregates_comment_deleted() -returns trigger language plpgsql -as $$ -begin - IF NEW.deleted = TRUE THEN - update post_aggregates pa - set comments = comments - 1 - where pa.post_id = NEW.post_id; - ELSE - update post_aggregates pa - set comments = comments + 1 - where pa.post_id = NEW.post_id; - END IF; - return null; -end $$; - -create trigger post_aggregates_comment_set_deleted -after update of deleted on comment -for each row -execute procedure post_aggregates_comment_deleted(); +CREATE TRIGGER post_aggregates_comment_set_deleted + AFTER UPDATE OF deleted ON comment + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_comment_deleted (); -- Fix issue with being able to necro-bump your own post -create or replace function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1, - newest_comment_time = NEW.published - where pa.post_id = NEW.post_id; +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1, + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time_necro = NEW.published + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = NEW.post_id + -- Fix issue with being able to necro-bump your own post + AND NEW.creator_id != p.creator_id + AND pa.published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time_necro = NEW.published - from post p - where pa.post_id = p.id - and pa.post_id = NEW.post_id - -- Fix issue with being able to necro-bump your own post - and NEW.creator_id != p.creator_id - and pa.published > ('now'::timestamp - '2 days'::interval); - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - ELSIF (TG_OP = 'UPDATE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; diff --git a/migrations/2021-08-04-223559_create_user_community_block/down.sql b/migrations/2021-08-04-223559_create_user_community_block/down.sql index eb5a35e5a..d7a184494 100644 --- a/migrations/2021-08-04-223559_create_user_community_block/down.sql +++ b/migrations/2021-08-04-223559_create_user_community_block/down.sql @@ -1,2 +1,4 @@ -drop table person_block; -drop table community_block; +DROP TABLE person_block; + +DROP TABLE community_block; + diff --git a/migrations/2021-08-04-223559_create_user_community_block/up.sql b/migrations/2021-08-04-223559_create_user_community_block/up.sql index cbcadc284..4e31196c6 100644 --- a/migrations/2021-08-04-223559_create_user_community_block/up.sql +++ b/migrations/2021-08-04-223559_create_user_community_block/up.sql @@ -1,15 +1,16 @@ -create table person_block ( - id serial primary key, - person_id int references person on update cascade on delete cascade not null, - target_id int references person on update cascade on delete cascade not null, - published timestamp not null default now(), - unique(person_id, target_id) +CREATE TABLE person_block ( + id serial PRIMARY KEY, + person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + target_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (person_id, target_id) ); -create table community_block ( - id serial primary key, - person_id int references person on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - published timestamp not null default now(), - unique(person_id, community_id) +CREATE TABLE community_block ( + id serial PRIMARY KEY, + person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (person_id, community_id) ); + diff --git a/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/down.sql b/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/down.sql index a0ec4bdd4..50ddcb3a6 100644 --- a/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/down.sql +++ b/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/down.sql @@ -1,42 +1,64 @@ -create or replace function community_aggregates_activity(i text) -returns table(count_ bigint, community_id_ integer) -language plpgsql -as -$$ -begin - return query - select count(*), community_id - from ( - select c.creator_id, p.community_id from comment c - inner join post p on c.post_id = p.id - where c.published > ('now'::timestamp - i::interval) - union - select p.creator_id, p.community_id from post p - where p.published > ('now'::timestamp - i::interval) - ) a - group by community_id; -end; +CREATE OR REPLACE FUNCTION community_aggregates_activity (i text) + RETURNS TABLE ( + count_ bigint, + community_id_ integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN query + SELECT + count(*), + community_id + FROM ( + SELECT + c.creator_id, + p.community_id + FROM + comment c + INNER JOIN post p ON c.post_id = p.id + WHERE + c.published > ('now'::timestamp - i::interval) + UNION + SELECT + p.creator_id, + p.community_id + FROM + post p + WHERE + p.published > ('now'::timestamp - i::interval)) a +GROUP BY + community_id; +END; $$; -create or replace function site_aggregates_activity(i text) returns integer - language plpgsql - as $$ -declare - count_ integer; -begin - select count(*) - into count_ - from ( - select c.creator_id from comment c - inner join person u on c.creator_id = u.id - where c.published > ('now'::timestamp - i::interval) - and u.local = true - union - select p.creator_id from post p - inner join person u on p.creator_id = u.id - where p.published > ('now'::timestamp - i::interval) - and u.local = true - ) a; - return count_; -end; +CREATE OR REPLACE FUNCTION site_aggregates_activity (i text) + RETURNS integer + LANGUAGE plpgsql + AS $$ +DECLARE + count_ integer; +BEGIN + SELECT + count(*) INTO count_ + FROM ( + SELECT + c.creator_id + FROM + comment c + INNER JOIN person u ON c.creator_id = u.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + UNION + SELECT + p.creator_id + FROM + post p + INNER JOIN person u ON p.creator_id = u.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND u.local = TRUE) a; + RETURN count_; +END; $$; + diff --git a/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/up.sql b/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/up.sql index 2aafc3693..26a49bd87 100644 --- a/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/up.sql +++ b/migrations/2021-08-16-004209_fix_remove_bots_from_aggregates/up.sql @@ -1,52 +1,73 @@ -- Make sure bots aren't included in aggregate counts - -create or replace function community_aggregates_activity(i text) -returns table(count_ bigint, community_id_ integer) -language plpgsql -as -$$ -begin - return query - select count(*), community_id - from ( - select c.creator_id, p.community_id from comment c - inner join post p on c.post_id = p.id - inner join person pe on c.creator_id = pe.id - where c.published > ('now'::timestamp - i::interval) - and pe.bot_account = false - union - select p.creator_id, p.community_id from post p - inner join person pe on p.creator_id = pe.id - where p.published > ('now'::timestamp - i::interval) - and pe.bot_account = false - ) a - group by community_id; -end; +CREATE OR REPLACE FUNCTION community_aggregates_activity (i text) + RETURNS TABLE ( + count_ bigint, + community_id_ integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN query + SELECT + count(*), + community_id + FROM ( + SELECT + c.creator_id, + p.community_id + FROM + comment c + INNER JOIN post p ON c.post_id = p.id + INNER JOIN person pe ON c.creator_id = pe.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND pe.bot_account = FALSE + UNION + SELECT + p.creator_id, + p.community_id + FROM + post p + INNER JOIN person pe ON p.creator_id = pe.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND pe.bot_account = FALSE) a +GROUP BY + community_id; +END; $$; -create or replace function site_aggregates_activity(i text) returns integer - language plpgsql - as $$ -declare - count_ integer; -begin - select count(*) - into count_ - from ( - select c.creator_id from comment c - inner join person u on c.creator_id = u.id - inner join person pe on c.creator_id = pe.id - where c.published > ('now'::timestamp - i::interval) - and u.local = true - and pe.bot_account = false - union - select p.creator_id from post p - inner join person u on p.creator_id = u.id - inner join person pe on p.creator_id = pe.id - where p.published > ('now'::timestamp - i::interval) - and u.local = true - and pe.bot_account = false - ) a; - return count_; -end; +CREATE OR REPLACE FUNCTION site_aggregates_activity (i text) + RETURNS integer + LANGUAGE plpgsql + AS $$ +DECLARE + count_ integer; +BEGIN + SELECT + count(*) INTO count_ + FROM ( + SELECT + c.creator_id + FROM + comment c + INNER JOIN person u ON c.creator_id = u.id + INNER JOIN person pe ON c.creator_id = pe.id + WHERE + c.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + AND pe.bot_account = FALSE + UNION + SELECT + p.creator_id + FROM + post p + INNER JOIN person u ON p.creator_id = u.id + INNER JOIN person pe ON p.creator_id = pe.id + WHERE + p.published > ('now'::timestamp - i::interval) + AND u.local = TRUE + AND pe.bot_account = FALSE) a; + RETURN count_; +END; $$; + diff --git a/migrations/2021-08-17-210508_create_mod_transfer_community/down.sql b/migrations/2021-08-17-210508_create_mod_transfer_community/down.sql index 8a2d8820a..477454334 100644 --- a/migrations/2021-08-17-210508_create_mod_transfer_community/down.sql +++ b/migrations/2021-08-17-210508_create_mod_transfer_community/down.sql @@ -1 +1,2 @@ -drop table mod_transfer_community; +DROP TABLE mod_transfer_community; + diff --git a/migrations/2021-08-17-210508_create_mod_transfer_community/up.sql b/migrations/2021-08-17-210508_create_mod_transfer_community/up.sql index b43cf1408..e023576dd 100644 --- a/migrations/2021-08-17-210508_create_mod_transfer_community/up.sql +++ b/migrations/2021-08-17-210508_create_mod_transfer_community/up.sql @@ -1,9 +1,10 @@ -- Add the mod_transfer_community log table -create table mod_transfer_community ( - id serial primary key, - mod_person_id int references person on update cascade on delete cascade not null, - other_person_id int references person on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - removed boolean default false, - when_ timestamp not null default now() +CREATE TABLE mod_transfer_community ( + id serial PRIMARY KEY, + mod_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + other_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + removed boolean DEFAULT FALSE, + when_ timestamp NOT NULL DEFAULT now() ); + diff --git a/migrations/2021-09-20-112945_jwt-secret/down.sql b/migrations/2021-09-20-112945_jwt-secret/down.sql index 61b21fbab..89350d96a 100644 --- a/migrations/2021-09-20-112945_jwt-secret/down.sql +++ b/migrations/2021-09-20-112945_jwt-secret/down.sql @@ -1 +1,2 @@ -drop table secret; +DROP TABLE secret; + diff --git a/migrations/2021-09-20-112945_jwt-secret/up.sql b/migrations/2021-09-20-112945_jwt-secret/up.sql index e9af9ef55..85797c7f3 100644 --- a/migrations/2021-09-20-112945_jwt-secret/up.sql +++ b/migrations/2021-09-20-112945_jwt-secret/up.sql @@ -1,9 +1,9 @@ -- generate a jwt secret -create extension if not exists pgcrypto; +CREATE EXTENSION IF NOT EXISTS pgcrypto; -create table secret( - id serial primary key, - jwt_secret varchar not null default gen_random_uuid() +CREATE TABLE secret ( + id serial PRIMARY KEY, + jwt_secret varchar NOT NULL DEFAULT gen_random_uuid () ); -insert into secret default values; +INSERT INTO secret DEFAULT VALUES; diff --git a/migrations/2021-10-01-141650_create_admin_purge/down.sql b/migrations/2021-10-01-141650_create_admin_purge/down.sql index 054923f6b..c542fe779 100644 --- a/migrations/2021-10-01-141650_create_admin_purge/down.sql +++ b/migrations/2021-10-01-141650_create_admin_purge/down.sql @@ -1,4 +1,8 @@ -drop table admin_purge_person; -drop table admin_purge_community; -drop table admin_purge_post; -drop table admin_purge_comment; +DROP TABLE admin_purge_person; + +DROP TABLE admin_purge_community; + +DROP TABLE admin_purge_post; + +DROP TABLE admin_purge_comment; + diff --git a/migrations/2021-10-01-141650_create_admin_purge/up.sql b/migrations/2021-10-01-141650_create_admin_purge/up.sql index 1eb6b3f17..a67e12fe2 100644 --- a/migrations/2021-10-01-141650_create_admin_purge/up.sql +++ b/migrations/2021-10-01-141650_create_admin_purge/up.sql @@ -1,31 +1,31 @@ -- Add the admin_purge tables - -create table admin_purge_person ( - id serial primary key, - admin_person_id int references person on update cascade on delete cascade not null, - reason text, - when_ timestamp not null default now() +CREATE TABLE admin_purge_person ( + id serial PRIMARY KEY, + admin_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + when_ timestamp NOT NULL DEFAULT now() ); -create table admin_purge_community ( - id serial primary key, - admin_person_id int references person on update cascade on delete cascade not null, - reason text, - when_ timestamp not null default now() +CREATE TABLE admin_purge_community ( + id serial PRIMARY KEY, + admin_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + when_ timestamp NOT NULL DEFAULT now() ); -create table admin_purge_post ( - id serial primary key, - admin_person_id int references person on update cascade on delete cascade not null, - community_id int references community on update cascade on delete cascade not null, - reason text, - when_ timestamp not null default now() +CREATE TABLE admin_purge_post ( + id serial PRIMARY KEY, + admin_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + when_ timestamp NOT NULL DEFAULT now() ); -create table admin_purge_comment ( - id serial primary key, - admin_person_id int references person on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - reason text, - when_ timestamp not null default now() +CREATE TABLE admin_purge_comment ( + id serial PRIMARY KEY, + admin_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + reason text, + when_ timestamp NOT NULL DEFAULT now() ); + diff --git a/migrations/2021-11-22-135324_add_activity_ap_id_index/down.sql b/migrations/2021-11-22-135324_add_activity_ap_id_index/down.sql index d2d3ad9dc..664d6cfed 100644 --- a/migrations/2021-11-22-135324_add_activity_ap_id_index/down.sql +++ b/migrations/2021-11-22-135324_add_activity_ap_id_index/down.sql @@ -1,5 +1,7 @@ -alter table activity alter column ap_id drop not null; +ALTER TABLE activity + ALTER COLUMN ap_id DROP NOT NULL; -create unique index idx_activity_unique_apid on activity ((data ->> 'id'::text)); +CREATE UNIQUE INDEX idx_activity_unique_apid ON activity ((data ->> 'id'::text)); + +DROP INDEX idx_activity_ap_id; -drop index idx_activity_ap_id; diff --git a/migrations/2021-11-22-135324_add_activity_ap_id_index/up.sql b/migrations/2021-11-22-135324_add_activity_ap_id_index/up.sql index 84530508e..6fa2cf569 100644 --- a/migrations/2021-11-22-135324_add_activity_ap_id_index/up.sql +++ b/migrations/2021-11-22-135324_add_activity_ap_id_index/up.sql @@ -1,22 +1,29 @@ - -- Delete the empty ap_ids -delete from activity where ap_id is null; +DELETE FROM activity +WHERE ap_id IS NULL; -- Make it required -alter table activity alter column ap_id set not null; +ALTER TABLE activity + ALTER COLUMN ap_id SET NOT NULL; -- Delete dupes, keeping the first one -delete from activity a using ( - select min(id) as id, ap_id - from activity - group by ap_id having count(*) > 1 -) b -where a.ap_id = b.ap_id -and a.id <> b.id; +DELETE FROM activity a USING ( + SELECT + min(id) AS id, + ap_id + FROM + activity + GROUP BY + ap_id + HAVING + count(*) > 1) b +WHERE + a.ap_id = b.ap_id + AND a.id <> b.id; -- The index -create unique index idx_activity_ap_id on activity(ap_id); +CREATE UNIQUE INDEX idx_activity_ap_id ON activity (ap_id); -- Drop the old index -drop index idx_activity_unique_apid; +DROP INDEX idx_activity_unique_apid; diff --git a/migrations/2021-11-22-143904_add_required_public_key/down.sql b/migrations/2021-11-22-143904_add_required_public_key/down.sql index 775d07d3c..a6101d0a7 100644 --- a/migrations/2021-11-22-143904_add_required_public_key/down.sql +++ b/migrations/2021-11-22-143904_add_required_public_key/down.sql @@ -1,2 +1,6 @@ -alter table community alter column public_key drop not null; -alter table person alter column public_key drop not null; +ALTER TABLE community + ALTER COLUMN public_key DROP NOT NULL; + +ALTER TABLE person + ALTER COLUMN public_key DROP NOT NULL; + diff --git a/migrations/2021-11-22-143904_add_required_public_key/up.sql b/migrations/2021-11-22-143904_add_required_public_key/up.sql index b2882561c..7776f88c8 100644 --- a/migrations/2021-11-22-143904_add_required_public_key/up.sql +++ b/migrations/2021-11-22-143904_add_required_public_key/up.sql @@ -1,7 +1,14 @@ -- Delete the empty public keys -delete from community where public_key is null; -delete from person where public_key is null; +DELETE FROM community +WHERE public_key IS NULL; + +DELETE FROM person +WHERE public_key IS NULL; -- Make it required -alter table community alter column public_key set not null; -alter table person alter column public_key set not null; +ALTER TABLE community + ALTER COLUMN public_key SET NOT NULL; + +ALTER TABLE person + ALTER COLUMN public_key SET NOT NULL; + diff --git a/migrations/2021-11-23-031528_add_report_published_index/down.sql b/migrations/2021-11-23-031528_add_report_published_index/down.sql index b5e9b51ca..33b4fecf8 100644 --- a/migrations/2021-11-23-031528_add_report_published_index/down.sql +++ b/migrations/2021-11-23-031528_add_report_published_index/down.sql @@ -1,2 +1,4 @@ -drop index idx_comment_report_published; -drop index idx_post_report_published; +DROP INDEX idx_comment_report_published; + +DROP INDEX idx_post_report_published; + diff --git a/migrations/2021-11-23-031528_add_report_published_index/up.sql b/migrations/2021-11-23-031528_add_report_published_index/up.sql index eb0c1220c..33492419e 100644 --- a/migrations/2021-11-23-031528_add_report_published_index/up.sql +++ b/migrations/2021-11-23-031528_add_report_published_index/up.sql @@ -1,2 +1,4 @@ -create index idx_comment_report_published on comment_report (published desc); -create index idx_post_report_published on post_report (published desc); +CREATE INDEX idx_comment_report_published ON comment_report (published DESC); + +CREATE INDEX idx_post_report_published ON post_report (published DESC); + diff --git a/migrations/2021-11-23-132840_email_verification/down.sql b/migrations/2021-11-23-132840_email_verification/down.sql index cd1eb7c29..0579873da 100644 --- a/migrations/2021-11-23-132840_email_verification/down.sql +++ b/migrations/2021-11-23-132840_email_verification/down.sql @@ -1,8 +1,16 @@ -- revert defaults from db for local user init -alter table local_user alter column theme set default 'darkly'; -alter table local_user alter column default_listing_type set default 1; +ALTER TABLE local_user + ALTER COLUMN theme SET DEFAULT 'darkly'; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type SET DEFAULT 1; -- remove tables and columns for optional email verification -alter table site drop column require_email_verification; -alter table local_user drop column email_verified; -drop table email_verification; +ALTER TABLE site + DROP COLUMN require_email_verification; + +ALTER TABLE local_user + DROP COLUMN email_verified; + +DROP TABLE email_verification; + diff --git a/migrations/2021-11-23-132840_email_verification/up.sql b/migrations/2021-11-23-132840_email_verification/up.sql index 29a20e00c..3b14b2a3f 100644 --- a/migrations/2021-11-23-132840_email_verification/up.sql +++ b/migrations/2021-11-23-132840_email_verification/up.sql @@ -1,14 +1,21 @@ -- use defaults from db for local user init -alter table local_user alter column theme set default 'browser'; -alter table local_user alter column default_listing_type set default 2; +ALTER TABLE local_user + ALTER COLUMN theme SET DEFAULT 'browser'; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type SET DEFAULT 2; -- add tables and columns for optional email verification -alter table site add column require_email_verification boolean not null default false; -alter table local_user add column email_verified boolean not null default false; +ALTER TABLE site + ADD COLUMN require_email_verification boolean NOT NULL DEFAULT FALSE; -create table email_verification ( - id serial primary key, - local_user_id int references local_user(id) on update cascade on delete cascade not null, - email text not null, - verification_token text not null +ALTER TABLE local_user + ADD COLUMN email_verified boolean NOT NULL DEFAULT FALSE; + +CREATE TABLE email_verification ( + id serial PRIMARY KEY, + local_user_id int REFERENCES local_user (id) ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + email text NOT NULL, + verification_token text NOT NULL ); + diff --git a/migrations/2021-11-23-153753_add_invite_only_columns/down.sql b/migrations/2021-11-23-153753_add_invite_only_columns/down.sql index 52a1a2808..22af54bf8 100644 --- a/migrations/2021-11-23-153753_add_invite_only_columns/down.sql +++ b/migrations/2021-11-23-153753_add_invite_only_columns/down.sql @@ -1,9 +1,16 @@ -- Add columns to site table -alter table site drop column require_application; -alter table site drop column application_question; -alter table site drop column private_instance; +ALTER TABLE site + DROP COLUMN require_application; + +ALTER TABLE site + DROP COLUMN application_question; + +ALTER TABLE site + DROP COLUMN private_instance; -- Add pending to local_user -alter table local_user drop column accepted_application; +ALTER TABLE local_user + DROP COLUMN accepted_application; + +DROP TABLE registration_application; -drop table registration_application; diff --git a/migrations/2021-11-23-153753_add_invite_only_columns/up.sql b/migrations/2021-11-23-153753_add_invite_only_columns/up.sql index b3f8a18dc..7e611b169 100644 --- a/migrations/2021-11-23-153753_add_invite_only_columns/up.sql +++ b/migrations/2021-11-23-153753_add_invite_only_columns/up.sql @@ -1,19 +1,26 @@ -- Add columns to site table -alter table site add column require_application boolean not null default false; -alter table site add column application_question text; -alter table site add column private_instance boolean not null default false; +ALTER TABLE site + ADD COLUMN require_application boolean NOT NULL DEFAULT FALSE; + +ALTER TABLE site + ADD COLUMN application_question text; + +ALTER TABLE site + ADD COLUMN private_instance boolean NOT NULL DEFAULT FALSE; -- Add pending to local_user -alter table local_user add column accepted_application boolean not null default false; +ALTER TABLE local_user + ADD COLUMN accepted_application boolean NOT NULL DEFAULT FALSE; -create table registration_application ( - id serial primary key, - local_user_id int references local_user on update cascade on delete cascade not null, - answer text not null, - admin_id int references person on update cascade on delete cascade, - deny_reason text, - published timestamp not null default now(), - unique(local_user_id) +CREATE TABLE registration_application ( + id serial PRIMARY KEY, + local_user_id int REFERENCES local_user ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + answer text NOT NULL, + admin_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE, + deny_reason text, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (local_user_id) ); -create index idx_registration_application_published on registration_application (published desc); +CREATE INDEX idx_registration_application_published ON registration_application (published DESC); + diff --git a/migrations/2021-12-09-225529_add_published_to_email_verification/down.sql b/migrations/2021-12-09-225529_add_published_to_email_verification/down.sql index 21405db11..64aaa8e06 100644 --- a/migrations/2021-12-09-225529_add_published_to_email_verification/down.sql +++ b/migrations/2021-12-09-225529_add_published_to_email_verification/down.sql @@ -1 +1,3 @@ -alter table email_verification drop column published; +ALTER TABLE email_verification + DROP COLUMN published; + diff --git a/migrations/2021-12-09-225529_add_published_to_email_verification/up.sql b/migrations/2021-12-09-225529_add_published_to_email_verification/up.sql index 79dd32bfb..6eb47af64 100644 --- a/migrations/2021-12-09-225529_add_published_to_email_verification/up.sql +++ b/migrations/2021-12-09-225529_add_published_to_email_verification/up.sql @@ -1 +1,3 @@ -alter table email_verification add column published timestamp not null default now(); +ALTER TABLE email_verification + ADD COLUMN published timestamp NOT NULL DEFAULT now(); + diff --git a/migrations/2021-12-14-181537_add_temporary_bans/down.sql b/migrations/2021-12-14-181537_add_temporary_bans/down.sql index 83a3715ec..fde33ab1b 100644 --- a/migrations/2021-12-14-181537_add_temporary_bans/down.sql +++ b/migrations/2021-12-14-181537_add_temporary_bans/down.sql @@ -1,7 +1,20 @@ -drop view person_alias_1, person_alias_2; +DROP VIEW person_alias_1, person_alias_2; -alter table person drop column ban_expires; -alter table community_person_ban drop column expires; +ALTER TABLE person + DROP COLUMN ban_expires; + +ALTER TABLE community_person_ban + DROP COLUMN expires; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; diff --git a/migrations/2021-12-14-181537_add_temporary_bans/up.sql b/migrations/2021-12-14-181537_add_temporary_bans/up.sql index 7e6338361..6b3ee2463 100644 --- a/migrations/2021-12-14-181537_add_temporary_bans/up.sql +++ b/migrations/2021-12-14-181537_add_temporary_bans/up.sql @@ -1,8 +1,21 @@ -- Add ban_expires to person, community_person_ban -alter table person add column ban_expires timestamp; -alter table community_person_ban add column expires timestamp; +ALTER TABLE person + ADD COLUMN ban_expires timestamp; -drop view person_alias_1, person_alias_2; -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +ALTER TABLE community_person_ban + ADD COLUMN expires timestamp; + +DROP VIEW person_alias_1, person_alias_2; + +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; diff --git a/migrations/2022-01-04-034553_add_hidden_column/down.sql b/migrations/2022-01-04-034553_add_hidden_column/down.sql index 55a054ae3..f6e9367c7 100644 --- a/migrations/2022-01-04-034553_add_hidden_column/down.sql +++ b/migrations/2022-01-04-034553_add_hidden_column/down.sql @@ -1,3 +1,5 @@ -alter table community drop column hidden; +ALTER TABLE community + DROP COLUMN hidden; + +DROP TABLE mod_hide_community; -drop table mod_hide_community; diff --git a/migrations/2022-01-04-034553_add_hidden_column/up.sql b/migrations/2022-01-04-034553_add_hidden_column/up.sql index b7436616d..8aa7321ee 100644 --- a/migrations/2022-01-04-034553_add_hidden_column/up.sql +++ b/migrations/2022-01-04-034553_add_hidden_column/up.sql @@ -1,13 +1,12 @@ -alter table community add column hidden boolean default false; +ALTER TABLE community + ADD COLUMN hidden boolean DEFAULT FALSE; - -create table mod_hide_community -( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - mod_person_id int references person on update cascade on delete cascade not null, - when_ timestamp not null default now(), +CREATE TABLE mod_hide_community ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + mod_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + when_ timestamp NOT NULL DEFAULT now(), reason text, - hidden boolean default false + hidden boolean DEFAULT FALSE ); diff --git a/migrations/2022-01-20-160328_remove_site_creator/down.sql b/migrations/2022-01-20-160328_remove_site_creator/down.sql index 8195f719b..612a51893 100644 --- a/migrations/2022-01-20-160328_remove_site_creator/down.sql +++ b/migrations/2022-01-20-160328_remove_site_creator/down.sql @@ -1,14 +1,22 @@ -- Add the column back -alter table site add column creator_id int references person on update cascade on delete cascade; +ALTER TABLE site + ADD COLUMN creator_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE; -- Add the data, selecting the highest admin -update site -set creator_id = sub.id -from ( - select id from person - where admin = true - limit 1 -) as sub; +UPDATE + site +SET + creator_id = sub.id +FROM ( + SELECT + id + FROM + person + WHERE + admin = TRUE + LIMIT 1) AS sub; -- Set to not null -alter table site alter column creator_id set not null; +ALTER TABLE site + ALTER COLUMN creator_id SET NOT NULL; + diff --git a/migrations/2022-01-20-160328_remove_site_creator/up.sql b/migrations/2022-01-20-160328_remove_site_creator/up.sql index 78774445b..5f11c56c4 100644 --- a/migrations/2022-01-20-160328_remove_site_creator/up.sql +++ b/migrations/2022-01-20-160328_remove_site_creator/up.sql @@ -1,2 +1,4 @@ -- Drop the column -alter table site drop column creator_id; +ALTER TABLE site + DROP COLUMN creator_id; + diff --git a/migrations/2022-01-28-104106_instance-actor/down.sql b/migrations/2022-01-28-104106_instance-actor/down.sql index a258c27a4..0a45515dc 100644 --- a/migrations/2022-01-28-104106_instance-actor/down.sql +++ b/migrations/2022-01-28-104106_instance-actor/down.sql @@ -1,6 +1,7 @@ -alter table site - drop column actor_id, - drop column last_refreshed_at, - drop column inbox_url, - drop column private_key, - drop column public_key; +ALTER TABLE site + DROP COLUMN actor_id, + DROP COLUMN last_refreshed_at, + DROP COLUMN inbox_url, + DROP COLUMN private_key, + DROP COLUMN public_key; + diff --git a/migrations/2022-01-28-104106_instance-actor/up.sql b/migrations/2022-01-28-104106_instance-actor/up.sql index 914ab757e..dcbb08625 100644 --- a/migrations/2022-01-28-104106_instance-actor/up.sql +++ b/migrations/2022-01-28-104106_instance-actor/up.sql @@ -1,6 +1,7 @@ -alter table site - add column actor_id varchar(255) not null unique default generate_unique_changeme(), - add column last_refreshed_at Timestamp not null default now(), - add column inbox_url varchar(255) not null default generate_unique_changeme(), - add column private_key text, - add column public_key text not null default generate_unique_changeme(); +ALTER TABLE site + ADD COLUMN actor_id varchar(255) NOT NULL UNIQUE DEFAULT generate_unique_changeme (), + ADD COLUMN last_refreshed_at Timestamp NOT NULL DEFAULT now(), + ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme (), + ADD COLUMN private_key text, + ADD COLUMN public_key text NOT NULL DEFAULT generate_unique_changeme (); + diff --git a/migrations/2022-02-01-154240_add_community_title_index/down.sql b/migrations/2022-02-01-154240_add_community_title_index/down.sql index 8b927b7b3..39c454ab5 100644 --- a/migrations/2022-02-01-154240_add_community_title_index/down.sql +++ b/migrations/2022-02-01-154240_add_community_title_index/down.sql @@ -1 +1,2 @@ -drop index idx_community_title; +DROP INDEX idx_community_title; + diff --git a/migrations/2022-02-01-154240_add_community_title_index/up.sql b/migrations/2022-02-01-154240_add_community_title_index/up.sql index 50c267bb4..4fe527181 100644 --- a/migrations/2022-02-01-154240_add_community_title_index/up.sql +++ b/migrations/2022-02-01-154240_add_community_title_index/up.sql @@ -1 +1,2 @@ -create index idx_community_title on community(title); +CREATE INDEX idx_community_title ON community (title); + diff --git a/migrations/2022-02-18-210946_default_theme/down.sql b/migrations/2022-02-18-210946_default_theme/down.sql index fc57669a8..a52305af7 100644 --- a/migrations/2022-02-18-210946_default_theme/down.sql +++ b/migrations/2022-02-18-210946_default_theme/down.sql @@ -1 +1,3 @@ -alter table site drop column default_theme; \ No newline at end of file +ALTER TABLE site + DROP COLUMN default_theme; + diff --git a/migrations/2022-02-18-210946_default_theme/up.sql b/migrations/2022-02-18-210946_default_theme/up.sql index dd6faad48..f2a2822ae 100644 --- a/migrations/2022-02-18-210946_default_theme/up.sql +++ b/migrations/2022-02-18-210946_default_theme/up.sql @@ -1 +1,3 @@ -alter table site add column default_theme text not null default 'browser'; \ No newline at end of file +ALTER TABLE site + ADD COLUMN default_theme text NOT NULL DEFAULT 'browser'; + diff --git a/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/down.sql b/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/down.sql index 8a8ea5cb2..406d459ae 100644 --- a/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/down.sql +++ b/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/down.sql @@ -1,254 +1,339 @@ -drop trigger if exists community_aggregates_post_count on post; -drop trigger if exists community_aggregates_comment_count on comment; -drop trigger if exists site_aggregates_comment_insert on comment; -drop trigger if exists site_aggregates_comment_delete on comment; -drop trigger if exists site_aggregates_post_insert on post; -drop trigger if exists site_aggregates_post_delete on post; -drop trigger if exists site_aggregates_community_insert on community; -drop trigger if exists site_aggregates_community_delete on community; -drop trigger if exists person_aggregates_post_count on post; -drop trigger if exists person_aggregates_comment_count on comment; +DROP TRIGGER IF EXISTS community_aggregates_post_count ON post; -drop function was_removed_or_deleted(TG_OP text, OLD record, NEW record); -drop function was_restored_or_created(TG_OP text, OLD record, NEW record); +DROP TRIGGER IF EXISTS community_aggregates_comment_count ON comment; + +DROP TRIGGER IF EXISTS site_aggregates_comment_insert ON comment; + +DROP TRIGGER IF EXISTS site_aggregates_comment_delete ON comment; + +DROP TRIGGER IF EXISTS site_aggregates_post_insert ON post; + +DROP TRIGGER IF EXISTS site_aggregates_post_delete ON post; + +DROP TRIGGER IF EXISTS site_aggregates_community_insert ON community; + +DROP TRIGGER IF EXISTS site_aggregates_community_delete ON community; + +DROP TRIGGER IF EXISTS person_aggregates_post_count ON post; + +DROP TRIGGER IF EXISTS person_aggregates_comment_count ON comment; + +DROP FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record); + +DROP FUNCTION was_restored_or_created (TG_OP text, OLD record, NEW record); -- Community aggregate functions +CREATE OR REPLACE FUNCTION community_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates + SET + posts = posts + 1 + WHERE + community_id = NEW.community_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates + SET + posts = posts - 1 + WHERE + community_id = OLD.community_id; + -- Update the counts if the post got deleted + UPDATE + community_aggregates ca + SET + posts = coalesce(cd.posts, 0), + comments = coalesce(cd.comments, 0) + FROM ( + SELECT + c.id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + community c + LEFT JOIN post p ON c.id = p.community_id + LEFT JOIN comment ct ON p.id = ct.post_id + GROUP BY + c.id) cd + WHERE + ca.community_id = OLD.community_id; + END IF; + RETURN NULL; +END +$$; -create or replace function community_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN -update community_aggregates -set posts = posts + 1 where community_id = NEW.community_id; -ELSIF (TG_OP = 'DELETE') THEN -update community_aggregates -set posts = posts - 1 where community_id = OLD.community_id; - --- Update the counts if the post got deleted -update community_aggregates ca -set posts = coalesce(cd.posts, 0), - comments = coalesce(cd.comments, 0) - from ( - select - c.id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from community c - left join post p on c.id = p.community_id - left join comment ct on p.id = ct.post_id - group by c.id - ) cd -where ca.community_id = OLD.community_id; -END IF; -return null; -end $$; - -create or replace function community_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN -update community_aggregates ca -set comments = comments + 1 from comment c, post p -where p.id = c.post_id - and p.id = NEW.post_id - and ca.community_id = p.community_id; -ELSIF (TG_OP = 'DELETE') THEN -update community_aggregates ca -set comments = comments - 1 from comment c, post p -where p.id = c.post_id - and p.id = OLD.post_id - and ca.community_id = p.community_id; - -END IF; -return null; -end $$; +CREATE OR REPLACE FUNCTION community_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + community_aggregates ca + SET + comments = comments + 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = NEW.post_id + AND ca.community_id = p.community_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + community_aggregates ca + SET + comments = comments - 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = OLD.post_id + AND ca.community_id = p.community_id; + END IF; + RETURN NULL; +END +$$; -- Community aggregate triggers +CREATE TRIGGER community_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_post_count (); -create trigger community_aggregates_post_count - after insert or delete on post -for each row -execute procedure community_aggregates_post_count(); - -create trigger community_aggregates_comment_count - after insert or delete on comment -for each row -execute procedure community_aggregates_comment_count(); +CREATE TRIGGER community_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_comment_count (); -- Site aggregate functions +CREATE OR REPLACE FUNCTION site_aggregates_post_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + posts = posts + 1; + RETURN NULL; +END +$$; -create or replace function site_aggregates_post_insert() - returns trigger language plpgsql -as $$ -begin -update site_aggregates -set posts = posts + 1; -return null; -end $$; +CREATE OR REPLACE FUNCTION site_aggregates_post_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + posts = posts - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create or replace function site_aggregates_post_delete() - returns trigger language plpgsql -as $$ -begin -update site_aggregates sa -set posts = posts - 1 - from site s -where sa.site_id = s.id; -return null; -end $$; +CREATE OR REPLACE FUNCTION site_aggregates_comment_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + comments = comments + 1; + RETURN NULL; +END +$$; -create or replace function site_aggregates_comment_insert() - returns trigger language plpgsql -as $$ -begin -update site_aggregates -set comments = comments + 1; -return null; -end $$; +CREATE OR REPLACE FUNCTION site_aggregates_comment_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + comments = comments - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -create or replace function site_aggregates_comment_delete() - returns trigger language plpgsql -as $$ -begin -update site_aggregates sa -set comments = comments - 1 - from site s -where sa.site_id = s.id; -return null; -end $$; - -create or replace function site_aggregates_community_insert() - returns trigger language plpgsql -as $$ -begin -update site_aggregates -set communities = communities + 1; -return null; -end $$; - -create or replace function site_aggregates_community_delete() - returns trigger language plpgsql -as $$ -begin -update site_aggregates sa -set communities = communities - 1 - from site s -where sa.site_id = s.id; -return null; -end $$; +CREATE OR REPLACE FUNCTION site_aggregates_community_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates + SET + communities = communities + 1; + RETURN NULL; +END +$$; +CREATE OR REPLACE FUNCTION site_aggregates_community_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + site_aggregates sa + SET + communities = communities - 1 + FROM + site s + WHERE + sa.site_id = s.id; + RETURN NULL; +END +$$; -- Site update triggers +CREATE TRIGGER site_aggregates_post_insert + AFTER INSERT ON post + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_insert (); -create trigger site_aggregates_post_insert - after insert on post - for each row - when (NEW.local = true) - execute procedure site_aggregates_post_insert(); +CREATE TRIGGER site_aggregates_post_delete + AFTER DELETE ON post + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_delete (); -create trigger site_aggregates_post_delete - after delete on post - for each row - when (OLD.local = true) - execute procedure site_aggregates_post_delete(); +CREATE TRIGGER site_aggregates_comment_insert + AFTER INSERT ON comment + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_insert (); -create trigger site_aggregates_comment_insert - after insert on comment - for each row - when (NEW.local = true) - execute procedure site_aggregates_comment_insert(); +CREATE TRIGGER site_aggregates_comment_delete + AFTER DELETE ON comment + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_delete (); -create trigger site_aggregates_comment_delete - after delete on comment - for each row - when (OLD.local = true) - execute procedure site_aggregates_comment_delete(); +CREATE TRIGGER site_aggregates_community_insert + AFTER INSERT ON community + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_insert (); -create trigger site_aggregates_community_insert - after insert on community - for each row - when (NEW.local = true) - execute procedure site_aggregates_community_insert(); - -create trigger site_aggregates_community_delete - after delete on community - for each row - when (OLD.local = true) - execute procedure site_aggregates_community_delete(); +CREATE TRIGGER site_aggregates_community_delete + AFTER DELETE ON community + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_delete (); -- Person aggregate functions - -create or replace function person_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin +CREATE OR REPLACE FUNCTION person_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN IF (TG_OP = 'INSERT') THEN -update person_aggregates -set post_count = post_count + 1 where person_id = NEW.creator_id; + UPDATE + person_aggregates + SET + post_count = post_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates + SET + post_count = post_count - 1 + WHERE + person_id = OLD.creator_id; + -- If the post gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + person_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + person u + LEFT JOIN post p ON u.id = p.creator_id + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.person_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; -ELSIF (TG_OP = 'DELETE') THEN -update person_aggregates -set post_count = post_count - 1 where person_id = OLD.creator_id; - --- If the post gets deleted, the score calculation trigger won't fire, --- so you need to re-calculate -update person_aggregates ua -set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from person u - left join post p on u.id = p.creator_id - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd -where ua.person_id = OLD.creator_id; - -END IF; -return null; -end $$; - -create or replace function person_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin +CREATE OR REPLACE FUNCTION person_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN IF (TG_OP = 'INSERT') THEN -update person_aggregates -set comment_count = comment_count + 1 where person_id = NEW.creator_id; -ELSIF (TG_OP = 'DELETE') THEN -update person_aggregates -set comment_count = comment_count - 1 where person_id = OLD.creator_id; - --- If the comment gets deleted, the score calculation trigger won't fire, --- so you need to re-calculate -update person_aggregates ua -set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from person u - left join comment c on u.id = c.creator_id - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd -where ua.person_id = OLD.creator_id; -END IF; -return null; -end $$; - + UPDATE + person_aggregates + SET + comment_count = comment_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (TG_OP = 'DELETE') THEN + UPDATE + person_aggregates + SET + comment_count = comment_count - 1 + WHERE + person_id = OLD.creator_id; + -- If the comment gets deleted, the score calculation trigger won't fire, + -- so you need to re-calculate + UPDATE + person_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + person u + LEFT JOIN comment c ON u.id = c.creator_id + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.person_id = OLD.creator_id; + END IF; + RETURN NULL; +END +$$; -- Person aggregate triggers +CREATE TRIGGER person_aggregates_post_count + AFTER INSERT OR DELETE ON post + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_post_count (); -create trigger person_aggregates_post_count - after insert or delete on post - for each row -execute procedure person_aggregates_post_count(); +CREATE TRIGGER person_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_comment_count (); -create trigger person_aggregates_comment_count - after insert or delete on comment - for each row -execute procedure person_aggregates_comment_count(); \ No newline at end of file diff --git a/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql b/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql index 472be541d..27fc66d17 100644 --- a/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql +++ b/migrations/2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql @@ -1,327 +1,445 @@ -drop trigger if exists community_aggregates_post_count on post; -drop trigger if exists community_aggregates_comment_count on comment; -drop trigger if exists site_aggregates_comment_insert on comment; -drop trigger if exists site_aggregates_comment_delete on comment; -drop trigger if exists site_aggregates_post_insert on post; -drop trigger if exists site_aggregates_post_delete on post; -drop trigger if exists site_aggregates_community_insert on community; -drop trigger if exists site_aggregates_community_delete on community; -drop trigger if exists person_aggregates_post_count on post; -drop trigger if exists person_aggregates_comment_count on comment; +DROP TRIGGER IF EXISTS community_aggregates_post_count ON post; -create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) -RETURNS boolean -LANGUAGE plpgsql -as $$ - begin - IF (TG_OP = 'INSERT') THEN - return false; - end if; +DROP TRIGGER IF EXISTS community_aggregates_comment_count ON comment; - IF (TG_OP = 'DELETE') THEN - return true; - end if; +DROP TRIGGER IF EXISTS site_aggregates_comment_insert ON comment; - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 'f' AND NEW.deleted = 't') OR - (OLD.removed = 'f' AND NEW.removed = 't') - ); -END $$; +DROP TRIGGER IF EXISTS site_aggregates_comment_delete ON comment; -create or replace function was_restored_or_created(TG_OP text, OLD record, NEW record) +DROP TRIGGER IF EXISTS site_aggregates_post_insert ON post; + +DROP TRIGGER IF EXISTS site_aggregates_post_delete ON post; + +DROP TRIGGER IF EXISTS site_aggregates_community_insert ON community; + +DROP TRIGGER IF EXISTS site_aggregates_community_delete ON community; + +DROP TRIGGER IF EXISTS person_aggregates_post_count ON post; + +DROP TRIGGER IF EXISTS person_aggregates_comment_count ON comment; + +CREATE OR REPLACE FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record) RETURNS boolean LANGUAGE plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - return false; - end if; - + AS $$ +BEGIN IF (TG_OP = 'INSERT') THEN - return true; - end if; + RETURN FALSE; + END IF; + IF (TG_OP = 'DELETE') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 'f' + AND NEW.deleted = 't') + OR (OLD.removed = 'f' + AND NEW.removed = 't')); +END +$$; - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 't' AND NEW.deleted = 'f') OR - (OLD.removed = 't' AND NEW.removed = 'f') - ); -END $$; +CREATE OR REPLACE FUNCTION was_restored_or_created (TG_OP text, OLD record, NEW record) + RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + RETURN FALSE; + END IF; + IF (TG_OP = 'INSERT') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 't' + AND NEW.deleted = 'f') + OR (OLD.removed = 't' + AND NEW.removed = 'f')); +END +$$; -- Community aggregate functions - -create or replace function community_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN -update community_aggregates -set posts = posts + 1 where community_id = NEW.community_id; - -IF (TG_OP = 'UPDATE') THEN - -- Post was restored, so restore comment counts as well - update community_aggregates ca - set posts = coalesce(cd.posts, 0), - comments = coalesce(cd.comments, 0) - from ( - select - c.id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from community c - left join post p on c.id = p.community_id and p.deleted = 'f' and p.removed = 'f' - left join comment ct on p.id = ct.post_id and ct.deleted = 'f' and ct.removed = 'f' - where c.id = NEW.community_id - group by c.id - ) cd - where ca.community_id = NEW.community_id; -END IF; - -ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN -update community_aggregates -set posts = posts - 1 where community_id = OLD.community_id; - --- Update the counts if the post got deleted -update community_aggregates ca -set posts = coalesce(cd.posts, 0), - comments = coalesce(cd.comments, 0) - from ( - select - c.id, - count(distinct p.id) as posts, - count(distinct ct.id) as comments - from community c - left join post p on c.id = p.community_id and p.deleted = 'f' and p.removed = 'f' - left join comment ct on p.id = ct.post_id and ct.deleted = 'f' and ct.removed = 'f' - where c.id = OLD.community_id - group by c.id - ) cd -where ca.community_id = OLD.community_id; -END IF; -return null; -end $$; +CREATE OR REPLACE FUNCTION community_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates + SET + posts = posts + 1 + WHERE + community_id = NEW.community_id; + IF (TG_OP = 'UPDATE') THEN + -- Post was restored, so restore comment counts as well + UPDATE + community_aggregates ca + SET + posts = coalesce(cd.posts, 0), + comments = coalesce(cd.comments, 0) + FROM ( + SELECT + c.id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + community c + LEFT JOIN post p ON c.id = p.community_id + AND p.deleted = 'f' + AND p.removed = 'f' + LEFT JOIN comment ct ON p.id = ct.post_id + AND ct.deleted = 'f' + AND ct.removed = 'f' + WHERE + c.id = NEW.community_id + GROUP BY + c.id) cd + WHERE + ca.community_id = NEW.community_id; + END IF; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates + SET + posts = posts - 1 + WHERE + community_id = OLD.community_id; + -- Update the counts if the post got deleted + UPDATE + community_aggregates ca + SET + posts = coalesce(cd.posts, 0), + comments = coalesce(cd.comments, 0) + FROM ( + SELECT + c.id, + count(DISTINCT p.id) AS posts, + count(DISTINCT ct.id) AS comments + FROM + community c + LEFT JOIN post p ON c.id = p.community_id + AND p.deleted = 'f' + AND p.removed = 'f' + LEFT JOIN comment ct ON p.id = ct.post_id + AND ct.deleted = 'f' + AND ct.removed = 'f' + WHERE + c.id = OLD.community_id + GROUP BY + c.id) cd + WHERE + ca.community_id = OLD.community_id; + END IF; + RETURN NULL; +END +$$; -- comment count -create or replace function community_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments + 1 from comment c, post p -where p.id = c.post_id - and p.id = NEW.post_id - and ca.community_id = p.community_id; -ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments - 1 from comment c, post p -where p.id = c.post_id - and p.id = OLD.post_id - and ca.community_id = p.community_id; - -END IF; -return null; -end $$; +CREATE OR REPLACE FUNCTION community_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments + 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = NEW.post_id + AND ca.community_id = p.community_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments - 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = OLD.post_id + AND ca.community_id = p.community_id; + END IF; + RETURN NULL; +END +$$; -- Community aggregate triggers +CREATE TRIGGER community_aggregates_post_count + AFTER INSERT OR DELETE OR UPDATE OF removed, + deleted ON post + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_post_count (); -create trigger community_aggregates_post_count - after insert or delete or update of removed, deleted on post - for each row -execute procedure community_aggregates_post_count(); - -create trigger community_aggregates_comment_count - after insert or delete or update of removed, deleted on comment -for each row -execute procedure community_aggregates_comment_count(); +CREATE TRIGGER community_aggregates_comment_count + AFTER INSERT OR DELETE OR UPDATE OF removed, + deleted ON comment + FOR EACH ROW + EXECUTE PROCEDURE community_aggregates_comment_count (); -- Site aggregate functions - -create or replace function site_aggregates_post_insert() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set posts = posts + 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_post_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + posts = posts + 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function site_aggregates_post_delete() - returns trigger language plpgsql -as $$ -begin - IF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set posts = posts - 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_post_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + posts = posts - 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function site_aggregates_comment_insert() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set comments = comments + 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_comment_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + comments = comments + 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function site_aggregates_comment_delete() - returns trigger language plpgsql -as $$ -begin - IF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set comments = comments - 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_comment_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + comments = comments - 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function site_aggregates_community_insert() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set communities = communities + 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_community_insert () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + communities = communities + 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function site_aggregates_community_delete() - returns trigger language plpgsql -as $$ -begin - IF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update site_aggregates sa - set communities = communities - 1 - from site s - where sa.site_id = s.id; +CREATE OR REPLACE FUNCTION site_aggregates_community_delete () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + site_aggregates sa + SET + communities = communities - 1 + FROM + site s + WHERE + sa.site_id = s.id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -- Site aggregate triggers +CREATE TRIGGER site_aggregates_post_insert + AFTER INSERT OR UPDATE OF removed, + deleted ON post + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_insert (); -create trigger site_aggregates_post_insert - after insert or update of removed, deleted on post - for each row - when (NEW.local = true) -execute procedure site_aggregates_post_insert(); +CREATE TRIGGER site_aggregates_post_delete + AFTER DELETE OR UPDATE OF removed, + deleted ON post + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_post_delete (); -create trigger site_aggregates_post_delete - after delete or update of removed, deleted on post - for each row - when (OLD.local = true) -execute procedure site_aggregates_post_delete(); +CREATE TRIGGER site_aggregates_comment_insert + AFTER INSERT OR UPDATE OF removed, + deleted ON comment + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_insert (); -create trigger site_aggregates_comment_insert - after insert or update of removed, deleted on comment - for each row - when (NEW.local = true) -execute procedure site_aggregates_comment_insert(); +CREATE TRIGGER site_aggregates_comment_delete + AFTER DELETE OR UPDATE OF removed, + deleted ON comment + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_comment_delete (); -create trigger site_aggregates_comment_delete - after delete or update of removed, deleted on comment - for each row - when (OLD.local = true) -execute procedure site_aggregates_comment_delete(); +CREATE TRIGGER site_aggregates_community_insert + AFTER INSERT OR UPDATE OF removed, + deleted ON community + FOR EACH ROW + WHEN (NEW.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_insert (); -create trigger site_aggregates_community_insert - after insert or update of removed, deleted on community - for each row - when (NEW.local = true) -execute procedure site_aggregates_community_insert(); - -create trigger site_aggregates_community_delete - after delete or update of removed, deleted on community - for each row - when (OLD.local = true) -execute procedure site_aggregates_community_delete(); +CREATE TRIGGER site_aggregates_community_delete + AFTER DELETE OR UPDATE OF removed, + deleted ON community + FOR EACH ROW + WHEN (OLD.local = TRUE) + EXECUTE PROCEDURE site_aggregates_community_delete (); -- Person aggregate functions - -create or replace function person_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count + 1 where person_id = NEW.creator_id; - - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count - 1 where person_id = OLD.creator_id; - +CREATE OR REPLACE FUNCTION person_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count - 1 + WHERE + person_id = OLD.creator_id; -- If the post gets deleted, the score calculation trigger won't fire, -- so you need to re-calculate - update person_aggregates ua - set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from person u - left join post p on u.id = p.creator_id and p.deleted = 'f' and p.removed = 'f' - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd - where ua.person_id = OLD.creator_id; - + UPDATE + person_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + person u + LEFT JOIN post p ON u.id = p.creator_id + AND p.deleted = 'f' + AND p.removed = 'f' + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.person_id = OLD.creator_id; END IF; - return null; -end $$; - -create or replace function person_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count + 1 where person_id = NEW.creator_id; - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count - 1 where person_id = OLD.creator_id; + RETURN NULL; +END +$$; +CREATE OR REPLACE FUNCTION person_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count - 1 + WHERE + person_id = OLD.creator_id; -- If the comment gets deleted, the score calculation trigger won't fire, -- so you need to re-calculate - update person_aggregates ua - set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from person u - left join comment c on u.id = c.creator_id and c.deleted = 'f' and c.removed = 'f' - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd - where ua.person_id = OLD.creator_id; + UPDATE + person_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + person u + LEFT JOIN comment c ON u.id = c.creator_id + AND c.deleted = 'f' + AND c.removed = 'f' + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.person_id = OLD.creator_id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -- Person aggregate triggers +CREATE TRIGGER person_aggregates_post_count + AFTER INSERT OR DELETE OR UPDATE OF removed, + deleted ON post + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_post_count (); -create trigger person_aggregates_post_count - after insert or delete or update of removed, deleted on post - for each row -execute procedure person_aggregates_post_count(); +CREATE TRIGGER person_aggregates_comment_count + AFTER INSERT OR DELETE OR UPDATE OF removed, + deleted ON comment + FOR EACH ROW + EXECUTE PROCEDURE person_aggregates_comment_count (); -create trigger person_aggregates_comment_count - after insert or delete or update of removed, deleted on comment - for each row -execute procedure person_aggregates_comment_count(); diff --git a/migrations/2022-04-11-210137_fix_unique_changeme/down.sql b/migrations/2022-04-11-210137_fix_unique_changeme/down.sql index 28198e892..00aa1c719 100644 --- a/migrations/2022-04-11-210137_fix_unique_changeme/down.sql +++ b/migrations/2022-04-11-210137_fix_unique_changeme/down.sql @@ -1,6 +1,10 @@ -create or replace function generate_unique_changeme() -returns text language sql -as $$ - select 'http://changeme_' || string_agg (substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil (random() * 62)::integer, 1), '') - from generate_series(1, 20) +CREATE OR REPLACE FUNCTION generate_unique_changeme () + RETURNS text + LANGUAGE sql + AS $$ + SELECT + 'http://changeme_' || string_agg(substr('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789', ceil(random() * 62)::integer, 1), '') + FROM + generate_series(1, 20) $$; + diff --git a/migrations/2022-04-11-210137_fix_unique_changeme/up.sql b/migrations/2022-04-11-210137_fix_unique_changeme/up.sql index 46fe55b5f..5cd927d24 100644 --- a/migrations/2022-04-11-210137_fix_unique_changeme/up.sql +++ b/migrations/2022-04-11-210137_fix_unique_changeme/up.sql @@ -1,5 +1,8 @@ -create or replace function generate_unique_changeme() -returns text language sql -as $$ - select 'http://changeme.invalid/' || substr(md5(random()::text), 0, 25); +CREATE OR REPLACE FUNCTION generate_unique_changeme () + RETURNS text + LANGUAGE sql + AS $$ + SELECT + 'http://changeme.invalid/' || substr(md5(random()::text), 0, 25); $$; + diff --git a/migrations/2022-04-12-114352_default_post_listing_type/down.sql b/migrations/2022-04-12-114352_default_post_listing_type/down.sql index b70a7dd0c..9d51d7ca5 100644 --- a/migrations/2022-04-12-114352_default_post_listing_type/down.sql +++ b/migrations/2022-04-12-114352_default_post_listing_type/down.sql @@ -1 +1,3 @@ -alter table site drop column default_post_listing_type; +ALTER TABLE site + DROP COLUMN default_post_listing_type; + diff --git a/migrations/2022-04-12-114352_default_post_listing_type/up.sql b/migrations/2022-04-12-114352_default_post_listing_type/up.sql index f68e198fa..7cd0602ea 100644 --- a/migrations/2022-04-12-114352_default_post_listing_type/up.sql +++ b/migrations/2022-04-12-114352_default_post_listing_type/up.sql @@ -1 +1,3 @@ -alter table site add column default_post_listing_type text not null default 'Local'; +ALTER TABLE site + ADD COLUMN default_post_listing_type text NOT NULL DEFAULT 'Local'; + diff --git a/migrations/2022-04-12-185205_change_default_listing_type_to_local/down.sql b/migrations/2022-04-12-185205_change_default_listing_type_to_local/down.sql index d1d35659a..573677a9a 100644 --- a/migrations/2022-04-12-185205_change_default_listing_type_to_local/down.sql +++ b/migrations/2022-04-12-185205_change_default_listing_type_to_local/down.sql @@ -1,3 +1,4 @@ -- 0 is All, 1 is Local, 2 is Subscribed +ALTER TABLE ONLY local_user + ALTER COLUMN default_listing_type SET DEFAULT 2; -alter table only local_user alter column default_listing_type set default 2; diff --git a/migrations/2022-04-12-185205_change_default_listing_type_to_local/up.sql b/migrations/2022-04-12-185205_change_default_listing_type_to_local/up.sql index 15f0509e9..a0054a26d 100644 --- a/migrations/2022-04-12-185205_change_default_listing_type_to_local/up.sql +++ b/migrations/2022-04-12-185205_change_default_listing_type_to_local/up.sql @@ -1,3 +1,4 @@ -- 0 is All, 1 is Local, 2 is Subscribed +ALTER TABLE ONLY local_user + ALTER COLUMN default_listing_type SET DEFAULT 1; -alter table only local_user alter column default_listing_type set default 1; diff --git a/migrations/2022-04-19-111004_default_require_application/down.sql b/migrations/2022-04-19-111004_default_require_application/down.sql index eaa29a3ca..1fb993482 100644 --- a/migrations/2022-04-19-111004_default_require_application/down.sql +++ b/migrations/2022-04-19-111004_default_require_application/down.sql @@ -1,2 +1,6 @@ -alter table site alter column require_application set default false; -alter table site alter column application_question set default null; \ No newline at end of file +ALTER TABLE site + ALTER COLUMN require_application SET DEFAULT FALSE; + +ALTER TABLE site + ALTER COLUMN application_question SET DEFAULT NULL; + diff --git a/migrations/2022-04-19-111004_default_require_application/up.sql b/migrations/2022-04-19-111004_default_require_application/up.sql index 1e326f173..35722288f 100644 --- a/migrations/2022-04-19-111004_default_require_application/up.sql +++ b/migrations/2022-04-19-111004_default_require_application/up.sql @@ -1,2 +1,6 @@ -alter table site alter column require_application set default true; -alter table site alter column application_question set default 'To verify that you are human, please explain why you want to create an account on this site'; \ No newline at end of file +ALTER TABLE site + ALTER COLUMN require_application SET DEFAULT TRUE; + +ALTER TABLE site + ALTER COLUMN application_question SET DEFAULT 'To verify that you are human, please explain why you want to create an account on this site'; + diff --git a/migrations/2022-04-26-105145_only_mod_can_post/down.sql b/migrations/2022-04-26-105145_only_mod_can_post/down.sql index a9c95bf62..c74fe40ca 100644 --- a/migrations/2022-04-26-105145_only_mod_can_post/down.sql +++ b/migrations/2022-04-26-105145_only_mod_can_post/down.sql @@ -1 +1,3 @@ -alter table community drop column posting_restricted_to_mods; \ No newline at end of file +ALTER TABLE community + DROP COLUMN posting_restricted_to_mods; + diff --git a/migrations/2022-04-26-105145_only_mod_can_post/up.sql b/migrations/2022-04-26-105145_only_mod_can_post/up.sql index fbc569831..176de3cb3 100644 --- a/migrations/2022-04-26-105145_only_mod_can_post/up.sql +++ b/migrations/2022-04-26-105145_only_mod_can_post/up.sql @@ -1 +1,3 @@ -alter table community add column posting_restricted_to_mods boolean default false; \ No newline at end of file +ALTER TABLE community + ADD COLUMN posting_restricted_to_mods boolean DEFAULT FALSE; + diff --git a/migrations/2022-05-19-153931_legal-information/down.sql b/migrations/2022-05-19-153931_legal-information/down.sql index 0df8c19ef..f8a398e62 100644 --- a/migrations/2022-05-19-153931_legal-information/down.sql +++ b/migrations/2022-05-19-153931_legal-information/down.sql @@ -1 +1,3 @@ -alter table site drop column legal_information; \ No newline at end of file +ALTER TABLE site + DROP COLUMN legal_information; + diff --git a/migrations/2022-05-19-153931_legal-information/up.sql b/migrations/2022-05-19-153931_legal-information/up.sql index 641fe63f7..01266d0f8 100644 --- a/migrations/2022-05-19-153931_legal-information/up.sql +++ b/migrations/2022-05-19-153931_legal-information/up.sql @@ -1 +1,3 @@ -alter table site add column legal_information text; \ No newline at end of file +ALTER TABLE site + ADD COLUMN legal_information text; + diff --git a/migrations/2022-05-20-135341_embed-url/down.sql b/migrations/2022-05-20-135341_embed-url/down.sql index 1c4ff1f61..4ce7051a1 100644 --- a/migrations/2022-05-20-135341_embed-url/down.sql +++ b/migrations/2022-05-20-135341_embed-url/down.sql @@ -1,2 +1,6 @@ -alter table post drop column embed_url; -alter table post add column embed_video_url text; \ No newline at end of file +ALTER TABLE post + DROP COLUMN embed_url; + +ALTER TABLE post + ADD COLUMN embed_video_url text; + diff --git a/migrations/2022-05-20-135341_embed-url/up.sql b/migrations/2022-05-20-135341_embed-url/up.sql index 47d0df683..d69c0f311 100644 --- a/migrations/2022-05-20-135341_embed-url/up.sql +++ b/migrations/2022-05-20-135341_embed-url/up.sql @@ -1,2 +1,6 @@ -alter table post drop column embed_html; -alter table post add column embed_video_url text; \ No newline at end of file +ALTER TABLE post + DROP COLUMN embed_html; + +ALTER TABLE post + ADD COLUMN embed_video_url text; + diff --git a/migrations/2022-06-12-012121_add_site_hide_modlog_names/down.sql b/migrations/2022-06-12-012121_add_site_hide_modlog_names/down.sql index c3f658175..d758752d4 100644 --- a/migrations/2022-06-12-012121_add_site_hide_modlog_names/down.sql +++ b/migrations/2022-06-12-012121_add_site_hide_modlog_names/down.sql @@ -1 +1,3 @@ -alter table site drop column hide_modlog_mod_names; \ No newline at end of file +ALTER TABLE site + DROP COLUMN hide_modlog_mod_names; + diff --git a/migrations/2022-06-12-012121_add_site_hide_modlog_names/up.sql b/migrations/2022-06-12-012121_add_site_hide_modlog_names/up.sql index 329ad6f42..bb8e65644 100644 --- a/migrations/2022-06-12-012121_add_site_hide_modlog_names/up.sql +++ b/migrations/2022-06-12-012121_add_site_hide_modlog_names/up.sql @@ -1 +1,3 @@ -alter table site add column hide_modlog_mod_names boolean default true NOT NULL; \ No newline at end of file +ALTER TABLE site + ADD COLUMN hide_modlog_mod_names boolean DEFAULT TRUE NOT NULL; + diff --git a/migrations/2022-06-13-124806_post_report_name_length/down.sql b/migrations/2022-06-13-124806_post_report_name_length/down.sql index f7b3a95e6..7f99a59ca 100644 --- a/migrations/2022-06-13-124806_post_report_name_length/down.sql +++ b/migrations/2022-06-13-124806_post_report_name_length/down.sql @@ -1 +1,3 @@ -alter table post_report alter column original_post_name type varchar(100); +ALTER TABLE post_report + ALTER COLUMN original_post_name TYPE varchar(100); + diff --git a/migrations/2022-06-13-124806_post_report_name_length/up.sql b/migrations/2022-06-13-124806_post_report_name_length/up.sql index 766311512..595b1337f 100644 --- a/migrations/2022-06-13-124806_post_report_name_length/up.sql +++ b/migrations/2022-06-13-124806_post_report_name_length/up.sql @@ -1,2 +1,4 @@ -- adjust length limit to match post.name -alter table post_report alter column original_post_name type varchar(200); +ALTER TABLE post_report + ALTER COLUMN original_post_name TYPE varchar(200); + diff --git a/migrations/2022-06-21-123144_language-tags/down.sql b/migrations/2022-06-21-123144_language-tags/down.sql index 22ce261fa..8af971d0c 100644 --- a/migrations/2022-06-21-123144_language-tags/down.sql +++ b/migrations/2022-06-21-123144_language-tags/down.sql @@ -1,6 +1,9 @@ -alter table post drop column language_id; -drop table local_user_language; -drop table language; +ALTER TABLE post + DROP COLUMN language_id; -alter table local_user rename column interface_language to lang; +DROP TABLE local_user_language; + +DROP TABLE LANGUAGE; + +ALTER TABLE local_user RENAME COLUMN interface_language TO lang; diff --git a/migrations/2022-06-21-123144_language-tags/up.sql b/migrations/2022-06-21-123144_language-tags/up.sql index e670a59d4..9deb6b479 100644 --- a/migrations/2022-06-21-123144_language-tags/up.sql +++ b/migrations/2022-06-21-123144_language-tags/up.sql @@ -1,199 +1,758 @@ -create table language ( - id serial primary key, - code varchar(3), - name text -); -create table local_user_language ( - id serial primary key, - local_user_id int references local_user on update cascade on delete cascade not null, - language_id int references language on update cascade on delete cascade not null, - unique (local_user_id, language_id) +CREATE TABLE +LANGUAGE ( + id serial PRIMARY KEY, + code varchar(3), + name text ); -alter table local_user rename column lang to interface_language; +CREATE TABLE local_user_language ( + id serial PRIMARY KEY, + local_user_id int REFERENCES local_user ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + language_id int REFERENCES + LANGUAGE ON + UPDATE CASCADE ON DELETE CASCADE NOT NULL, + UNIQUE (local_user_id, language_id) +); + +ALTER TABLE local_user RENAME COLUMN lang TO interface_language; + +INSERT INTO +LANGUAGE (id, code, name) + VALUES (0, 'und', 'Undetermined'); + +ALTER TABLE post + ADD COLUMN language_id integer REFERENCES LANGUAGE NOT + NULL DEFAULT 0; + +INSERT INTO +LANGUAGE (code, name) + VALUES ('aa', 'Afaraf'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ab', 'аҧсуа бызшәа'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ae', 'avesta'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('af', 'Afrikaans'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ak', 'Akan'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('am', 'አማርኛ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('an', 'aragonés'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ar', 'اَلْعَرَبِيَّةُ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('as', 'অসমীয়া'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('av', 'авар мацӀ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ay', 'aymar aru'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('az', 'azərbaycan dili'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ba', 'башҡорт теле'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('be', 'беларуская мова'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bg', 'български език'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bi', 'Bislama'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bm', 'bamanankan'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bn', 'বাংলা'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bo', 'བོད་ཡིག'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('br', 'brezhoneg'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('bs', 'bosanski jezik'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ca', 'Català'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ce', 'нохчийн мотт'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ch', 'Chamoru'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('co', 'corsu'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('cr', 'ᓀᐦᐃᔭᐍᐏᐣ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('cs', 'čeština'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('cu', 'ѩзыкъ словѣньскъ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('cv', 'чӑваш чӗлхи'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('cy', 'Cymraeg'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('da', 'dansk'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('de', 'Deutsch'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('dv', 'ދިވެހި'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('dz', 'རྫོང་ཁ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ee', 'Eʋegbe'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('el', 'Ελληνικά'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('en', 'English'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('eo', 'Esperanto'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('es', 'Español'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('et', 'eesti'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('eu', 'euskara'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fa', 'فارسی'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ff', 'Fulfulde'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fi', 'suomi'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fj', 'vosa Vakaviti'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fo', 'føroyskt'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fr', 'Français'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('fy', 'Frysk'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ga', 'Gaeilge'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('gd', 'Gàidhlig'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('gl', 'galego'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('gn', E'Avañe\'ẽ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('gu', 'ગુજરાતી'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('gv', 'Gaelg'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ha', 'هَوُسَ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('he', 'עברית'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('hi', 'हिन्दी'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ho', 'Hiri Motu'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('hr', 'Hrvatski'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ht', 'Kreyòl ayisyen'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('hu', 'magyar'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('hy', 'Հայերեն'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('hz', 'Otjiherero'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ia', 'Interlingua'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('id', 'Bahasa Indonesia'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ie', 'Interlingue'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ig', 'Asụsụ Igbo'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ii', 'ꆈꌠ꒿ Nuosuhxop'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ik', 'Iñupiaq'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('io', 'Ido'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('is', 'Íslenska'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('it', 'Italiano'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('iu', 'ᐃᓄᒃᑎᑐᑦ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ja', '日本語'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('jv', 'basa Jawa'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ka', 'ქართული'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kg', 'Kikongo'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ki', 'Gĩkũyũ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kj', 'Kuanyama'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kk', 'қазақ тілі'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kl', 'kalaallisut'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('km', 'ខេមរភាសា'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kn', 'ಕನ್ನಡ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ko', '한국어'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kr', 'Kanuri'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ks', 'कश्मीरी'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ku', 'Kurdî'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kv', 'коми кыв'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('kw', 'Kernewek'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ky', 'Кыргызча'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('la', 'latine'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lb', 'Lëtzebuergesch'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lg', 'Luganda'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('li', 'Limburgs'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ln', 'Lingála'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lo', 'ພາສາລາວ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lt', 'lietuvių kalba'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lu', 'Kiluba'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('lv', 'latviešu valoda'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mg', 'fiteny malagasy'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mh', 'Kajin M̧ajeļ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mi', 'te reo Māori'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mk', 'македонски јазик'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ml', 'മലയാളം'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mn', 'Монгол хэл'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mr', 'मराठी'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ms', 'Bahasa Melayu'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('mt', 'Malti'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('my', 'ဗမာစာ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('na', 'Dorerin Naoero'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nb', 'Norsk bokmål'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nd', 'isiNdebele'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ne', 'नेपाली'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ng', 'Owambo'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nl', 'Nederlands'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nn', 'Norsk nynorsk'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('no', 'Norsk'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nr', 'isiNdebele'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('nv', 'Diné bizaad'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ny', 'chiCheŵa'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('oc', 'occitan'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('oj', 'ᐊᓂᔑᓈᐯᒧᐎᓐ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('om', 'Afaan Oromoo'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('or', 'ଓଡ଼ିଆ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('os', 'ирон æвзаг'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('pa', 'ਪੰਜਾਬੀ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('pi', 'पाऴि'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('pl', 'Polski'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ps', 'پښتو'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('pt', 'Português'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('qu', 'Runa Simi'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('rm', 'rumantsch grischun'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('rn', 'Ikirundi'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ro', 'Română'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ru', 'Русский'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('rw', 'Ikinyarwanda'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sa', 'संस्कृतम्'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sc', 'sardu'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sd', 'सिन्धी'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('se', 'Davvisámegiella'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sg', 'yângâ tî sängö'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('si', 'සිංහල'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sk', 'slovenčina'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sl', 'slovenščina'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sm', E'gagana fa\'a Samoa'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sn', 'chiShona'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('so', 'Soomaaliga'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sq', 'Shqip'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sr', 'српски језик'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ss', 'SiSwati'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('st', 'Sesotho'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('su', 'Basa Sunda'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sv', 'Svenska'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('sw', 'Kiswahili'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ta', 'தமிழ்'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('te', 'తెలుగు'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tg', 'тоҷикӣ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('th', 'ไทย'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ti', 'ትግርኛ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tk', 'Türkmençe'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tl', 'Wikang Tagalog'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tn', 'Setswana'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('to', 'faka Tonga'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tr', 'Türkçe'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ts', 'Xitsonga'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tt', 'татар теле'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('tw', 'Twi'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ty', 'Reo Tahiti'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ug', 'ئۇيغۇرچە‎'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('uk', 'Українська'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ur', 'اردو'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('uz', 'Ўзбек'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('ve', 'Tshivenḓa'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('vi', 'Tiếng Việt'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('vo', 'Volapük'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('wa', 'walon'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('wo', 'Wollof'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('xh', 'isiXhosa'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('yi', 'ייִדיש'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('yo', 'Yorùbá'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('za', 'Saɯ cueŋƅ'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('zh', '中文'); + +INSERT INTO +LANGUAGE (code, name) + VALUES ('zu', 'isiZulu'); -insert into language(id, code, name) values (0, 'und', 'Undetermined'); -alter table post add column language_id integer references language not null default 0; -insert into language(code, name) values ('aa', 'Afaraf'); -insert into language(code, name) values ('ab', 'аҧсуа бызшәа'); -insert into language(code, name) values ('ae', 'avesta'); -insert into language(code, name) values ('af', 'Afrikaans'); -insert into language(code, name) values ('ak', 'Akan'); -insert into language(code, name) values ('am', 'አማርኛ'); -insert into language(code, name) values ('an', 'aragonés'); -insert into language(code, name) values ('ar', 'اَلْعَرَبِيَّةُ'); -insert into language(code, name) values ('as', 'অসমীয়া'); -insert into language(code, name) values ('av', 'авар мацӀ'); -insert into language(code, name) values ('ay', 'aymar aru'); -insert into language(code, name) values ('az', 'azərbaycan dili'); -insert into language(code, name) values ('ba', 'башҡорт теле'); -insert into language(code, name) values ('be', 'беларуская мова'); -insert into language(code, name) values ('bg', 'български език'); -insert into language(code, name) values ('bi', 'Bislama'); -insert into language(code, name) values ('bm', 'bamanankan'); -insert into language(code, name) values ('bn', 'বাংলা'); -insert into language(code, name) values ('bo', 'བོད་ཡིག'); -insert into language(code, name) values ('br', 'brezhoneg'); -insert into language(code, name) values ('bs', 'bosanski jezik'); -insert into language(code, name) values ('ca', 'Català'); -insert into language(code, name) values ('ce', 'нохчийн мотт'); -insert into language(code, name) values ('ch', 'Chamoru'); -insert into language(code, name) values ('co', 'corsu'); -insert into language(code, name) values ('cr', 'ᓀᐦᐃᔭᐍᐏᐣ'); -insert into language(code, name) values ('cs', 'čeština'); -insert into language(code, name) values ('cu', 'ѩзыкъ словѣньскъ'); -insert into language(code, name) values ('cv', 'чӑваш чӗлхи'); -insert into language(code, name) values ('cy', 'Cymraeg'); -insert into language(code, name) values ('da', 'dansk'); -insert into language(code, name) values ('de', 'Deutsch'); -insert into language(code, name) values ('dv', 'ދިވެހި'); -insert into language(code, name) values ('dz', 'རྫོང་ཁ'); -insert into language(code, name) values ('ee', 'Eʋegbe'); -insert into language(code, name) values ('el', 'Ελληνικά'); -insert into language(code, name) values ('en', 'English'); -insert into language(code, name) values ('eo', 'Esperanto'); -insert into language(code, name) values ('es', 'Español'); -insert into language(code, name) values ('et', 'eesti'); -insert into language(code, name) values ('eu', 'euskara'); -insert into language(code, name) values ('fa', 'فارسی'); -insert into language(code, name) values ('ff', 'Fulfulde'); -insert into language(code, name) values ('fi', 'suomi'); -insert into language(code, name) values ('fj', 'vosa Vakaviti'); -insert into language(code, name) values ('fo', 'føroyskt'); -insert into language(code, name) values ('fr', 'Français'); -insert into language(code, name) values ('fy', 'Frysk'); -insert into language(code, name) values ('ga', 'Gaeilge'); -insert into language(code, name) values ('gd', 'Gàidhlig'); -insert into language(code, name) values ('gl', 'galego'); -insert into language(code, name) values ('gn', E'Avañe\'ẽ'); -insert into language(code, name) values ('gu', 'ગુજરાતી'); -insert into language(code, name) values ('gv', 'Gaelg'); -insert into language(code, name) values ('ha', 'هَوُسَ'); -insert into language(code, name) values ('he', 'עברית'); -insert into language(code, name) values ('hi', 'हिन्दी'); -insert into language(code, name) values ('ho', 'Hiri Motu'); -insert into language(code, name) values ('hr', 'Hrvatski'); -insert into language(code, name) values ('ht', 'Kreyòl ayisyen'); -insert into language(code, name) values ('hu', 'magyar'); -insert into language(code, name) values ('hy', 'Հայերեն'); -insert into language(code, name) values ('hz', 'Otjiherero'); -insert into language(code, name) values ('ia', 'Interlingua'); -insert into language(code, name) values ('id', 'Bahasa Indonesia'); -insert into language(code, name) values ('ie', 'Interlingue'); -insert into language(code, name) values ('ig', 'Asụsụ Igbo'); -insert into language(code, name) values ('ii', 'ꆈꌠ꒿ Nuosuhxop'); -insert into language(code, name) values ('ik', 'Iñupiaq'); -insert into language(code, name) values ('io', 'Ido'); -insert into language(code, name) values ('is', 'Íslenska'); -insert into language(code, name) values ('it', 'Italiano'); -insert into language(code, name) values ('iu', 'ᐃᓄᒃᑎᑐᑦ'); -insert into language(code, name) values ('ja', '日本語'); -insert into language(code, name) values ('jv', 'basa Jawa'); -insert into language(code, name) values ('ka', 'ქართული'); -insert into language(code, name) values ('kg', 'Kikongo'); -insert into language(code, name) values ('ki', 'Gĩkũyũ'); -insert into language(code, name) values ('kj', 'Kuanyama'); -insert into language(code, name) values ('kk', 'қазақ тілі'); -insert into language(code, name) values ('kl', 'kalaallisut'); -insert into language(code, name) values ('km', 'ខេមរភាសា'); -insert into language(code, name) values ('kn', 'ಕನ್ನಡ'); -insert into language(code, name) values ('ko', '한국어'); -insert into language(code, name) values ('kr', 'Kanuri'); -insert into language(code, name) values ('ks', 'कश्मीरी'); -insert into language(code, name) values ('ku', 'Kurdî'); -insert into language(code, name) values ('kv', 'коми кыв'); -insert into language(code, name) values ('kw', 'Kernewek'); -insert into language(code, name) values ('ky', 'Кыргызча'); -insert into language(code, name) values ('la', 'latine'); -insert into language(code, name) values ('lb', 'Lëtzebuergesch'); -insert into language(code, name) values ('lg', 'Luganda'); -insert into language(code, name) values ('li', 'Limburgs'); -insert into language(code, name) values ('ln', 'Lingála'); -insert into language(code, name) values ('lo', 'ພາສາລາວ'); -insert into language(code, name) values ('lt', 'lietuvių kalba'); -insert into language(code, name) values ('lu', 'Kiluba'); -insert into language(code, name) values ('lv', 'latviešu valoda'); -insert into language(code, name) values ('mg', 'fiteny malagasy'); -insert into language(code, name) values ('mh', 'Kajin M̧ajeļ'); -insert into language(code, name) values ('mi', 'te reo Māori'); -insert into language(code, name) values ('mk', 'македонски јазик'); -insert into language(code, name) values ('ml', 'മലയാളം'); -insert into language(code, name) values ('mn', 'Монгол хэл'); -insert into language(code, name) values ('mr', 'मराठी'); -insert into language(code, name) values ('ms', 'Bahasa Melayu'); -insert into language(code, name) values ('mt', 'Malti'); -insert into language(code, name) values ('my', 'ဗမာစာ'); -insert into language(code, name) values ('na', 'Dorerin Naoero'); -insert into language(code, name) values ('nb', 'Norsk bokmål'); -insert into language(code, name) values ('nd', 'isiNdebele'); -insert into language(code, name) values ('ne', 'नेपाली'); -insert into language(code, name) values ('ng', 'Owambo'); -insert into language(code, name) values ('nl', 'Nederlands'); -insert into language(code, name) values ('nn', 'Norsk nynorsk'); -insert into language(code, name) values ('no', 'Norsk'); -insert into language(code, name) values ('nr', 'isiNdebele'); -insert into language(code, name) values ('nv', 'Diné bizaad'); -insert into language(code, name) values ('ny', 'chiCheŵa'); -insert into language(code, name) values ('oc', 'occitan'); -insert into language(code, name) values ('oj', 'ᐊᓂᔑᓈᐯᒧᐎᓐ'); -insert into language(code, name) values ('om', 'Afaan Oromoo'); -insert into language(code, name) values ('or', 'ଓଡ଼ିଆ'); -insert into language(code, name) values ('os', 'ирон æвзаг'); -insert into language(code, name) values ('pa', 'ਪੰਜਾਬੀ'); -insert into language(code, name) values ('pi', 'पाऴि'); -insert into language(code, name) values ('pl', 'Polski'); -insert into language(code, name) values ('ps', 'پښتو'); -insert into language(code, name) values ('pt', 'Português'); -insert into language(code, name) values ('qu', 'Runa Simi'); -insert into language(code, name) values ('rm', 'rumantsch grischun'); -insert into language(code, name) values ('rn', 'Ikirundi'); -insert into language(code, name) values ('ro', 'Română'); -insert into language(code, name) values ('ru', 'Русский'); -insert into language(code, name) values ('rw', 'Ikinyarwanda'); -insert into language(code, name) values ('sa', 'संस्कृतम्'); -insert into language(code, name) values ('sc', 'sardu'); -insert into language(code, name) values ('sd', 'सिन्धी'); -insert into language(code, name) values ('se', 'Davvisámegiella'); -insert into language(code, name) values ('sg', 'yângâ tî sängö'); -insert into language(code, name) values ('si', 'සිංහල'); -insert into language(code, name) values ('sk', 'slovenčina'); -insert into language(code, name) values ('sl', 'slovenščina'); -insert into language(code, name) values ('sm', E'gagana fa\'a Samoa'); -insert into language(code, name) values ('sn', 'chiShona'); -insert into language(code, name) values ('so', 'Soomaaliga'); -insert into language(code, name) values ('sq', 'Shqip'); -insert into language(code, name) values ('sr', 'српски језик'); -insert into language(code, name) values ('ss', 'SiSwati'); -insert into language(code, name) values ('st', 'Sesotho'); -insert into language(code, name) values ('su', 'Basa Sunda'); -insert into language(code, name) values ('sv', 'Svenska'); -insert into language(code, name) values ('sw', 'Kiswahili'); -insert into language(code, name) values ('ta', 'தமிழ்'); -insert into language(code, name) values ('te', 'తెలుగు'); -insert into language(code, name) values ('tg', 'тоҷикӣ'); -insert into language(code, name) values ('th', 'ไทย'); -insert into language(code, name) values ('ti', 'ትግርኛ'); -insert into language(code, name) values ('tk', 'Türkmençe'); -insert into language(code, name) values ('tl', 'Wikang Tagalog'); -insert into language(code, name) values ('tn', 'Setswana'); -insert into language(code, name) values ('to', 'faka Tonga'); -insert into language(code, name) values ('tr', 'Türkçe'); -insert into language(code, name) values ('ts', 'Xitsonga'); -insert into language(code, name) values ('tt', 'татар теле'); -insert into language(code, name) values ('tw', 'Twi'); -insert into language(code, name) values ('ty', 'Reo Tahiti'); -insert into language(code, name) values ('ug', 'ئۇيغۇرچە‎'); -insert into language(code, name) values ('uk', 'Українська'); -insert into language(code, name) values ('ur', 'اردو'); -insert into language(code, name) values ('uz', 'Ўзбек'); -insert into language(code, name) values ('ve', 'Tshivenḓa'); -insert into language(code, name) values ('vi', 'Tiếng Việt'); -insert into language(code, name) values ('vo', 'Volapük'); -insert into language(code, name) values ('wa', 'walon'); -insert into language(code, name) values ('wo', 'Wollof'); -insert into language(code, name) values ('xh', 'isiXhosa'); -insert into language(code, name) values ('yi', 'ייִדיש'); -insert into language(code, name) values ('yo', 'Yorùbá'); -insert into language(code, name) values ('za', 'Saɯ cueŋƅ'); -insert into language(code, name) values ('zh', '中文'); -insert into language(code, name) values ('zu', 'isiZulu'); diff --git a/migrations/2022-07-07-182650_comment_ltrees/down.sql b/migrations/2022-07-07-182650_comment_ltrees/down.sql index 6385f62c4..fce2e139b 100644 --- a/migrations/2022-07-07-182650_comment_ltrees/down.sql +++ b/migrations/2022-07-07-182650_comment_ltrees/down.sql @@ -1,25 +1,45 @@ -alter table comment add column parent_id integer; +ALTER TABLE comment + ADD COLUMN parent_id integer; -- Constraints and index -alter table comment add constraint comment_parent_id_fkey foreign key (parent_id) REFERENCES comment(id) ON UPDATE CASCADE ON DELETE CASCADE; -create index idx_comment_parent on comment (parent_id); +ALTER TABLE comment + ADD CONSTRAINT comment_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES comment (id) ON UPDATE CASCADE ON DELETE CASCADE; + +CREATE INDEX idx_comment_parent ON comment (parent_id); -- Update the parent_id column -- subpath(subpath(0, -1), -1) gets the immediate parent but it fails null checks -update comment set parent_id = cast(ltree2text(nullif(subpath(nullif(subpath(path, 0, -1), '0'), -1), '0')) as INTEGER); +UPDATE + comment +SET + parent_id = cast(ltree2text (nullif (subpath (nullif (subpath (path, 0, -1), '0'), -1), '0')) AS INTEGER); -alter table comment drop column path; -alter table comment_aggregates drop column child_count; +ALTER TABLE comment + DROP COLUMN path; -drop extension ltree; +ALTER TABLE comment_aggregates + DROP COLUMN child_count; + +DROP EXTENSION ltree; -- Add back in the read column -alter table comment add column read boolean default false not null; +ALTER TABLE comment + ADD COLUMN read boolean DEFAULT FALSE NOT NULL; -update comment c set read = cr.read -from comment_reply cr where cr.comment_id = c.id; +UPDATE + comment c +SET + read = cr.read +FROM + comment_reply cr +WHERE + cr.comment_id = c.id; -create view comment_alias_1 as select * from comment; +CREATE VIEW comment_alias_1 AS +SELECT + * +FROM + comment; -drop table comment_reply; +DROP TABLE comment_reply; diff --git a/migrations/2022-07-07-182650_comment_ltrees/up.sql b/migrations/2022-07-07-182650_comment_ltrees/up.sql index 4d2598dda..08c0141d3 100644 --- a/migrations/2022-07-07-182650_comment_ltrees/up.sql +++ b/migrations/2022-07-07-182650_comment_ltrees/up.sql @@ -1,118 +1,184 @@ -- Remove the comment.read column, and create a new comment_reply table, --- similar to the person_mention table. --- +-- similar to the person_mention table. +-- -- This is necessary because self-joins using ltrees would be too tough with SQL views --- --- Every comment should have a row here, because all comments have a recipient, +-- +-- Every comment should have a row here, because all comments have a recipient, -- either the post creator, or the parent commenter. -create table comment_reply( - id serial primary key, - recipient_id int references person on update cascade on delete cascade not null, - comment_id int references comment on update cascade on delete cascade not null, - read boolean default false not null, - published timestamp not null default now(), - unique(recipient_id, comment_id) +CREATE TABLE comment_reply ( + id serial PRIMARY KEY, + recipient_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + comment_id int REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + read boolean DEFAULT FALSE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (recipient_id, comment_id) ); -- Ones where parent_id is null, use the post creator recipient -insert into comment_reply (recipient_id, comment_id, read) -select p.creator_id, c.id, c.read from comment c -inner join post p on c.post_id = p.id -where c.parent_id is null; +INSERT INTO comment_reply (recipient_id, comment_id, read) +SELECT + p.creator_id, + c.id, + c.read +FROM + comment c + INNER JOIN post p ON c.post_id = p.id +WHERE + c.parent_id IS NULL; -- Ones where there is a parent_id, self join to comment to get the parent comment creator -insert into comment_reply (recipient_id, comment_id, read) -select c2.creator_id, c.id, c.read from comment c -inner join comment c2 on c.parent_id = c2.id; +INSERT INTO comment_reply (recipient_id, comment_id, read) +SELECT + c2.creator_id, + c.id, + c.read +FROM + comment c + INNER JOIN comment c2 ON c.parent_id = c2.id; -- Drop comment_alias view -drop view comment_alias_1; +DROP VIEW comment_alias_1; -alter table comment drop column read; +ALTER TABLE comment + DROP COLUMN read; -create extension if not exists ltree; +CREATE EXTENSION IF NOT EXISTS ltree; -alter table comment add column path ltree not null default '0'; -alter table comment_aggregates add column child_count integer not null default 0; +ALTER TABLE comment + ADD COLUMN path ltree NOT NULL DEFAULT '0'; --- The ltree path column should be the comment_id parent paths, separated by dots. +ALTER TABLE comment_aggregates + ADD COLUMN child_count integer NOT NULL DEFAULT 0; + +-- The ltree path column should be the comment_id parent paths, separated by dots. -- Stackoverflow: building an ltree from a parent_id hierarchical tree: -- https://stackoverflow.com/a/1144848/1655478 - -create temporary table comment_temp as +CREATE TEMPORARY TABLE comment_temp AS WITH RECURSIVE q AS ( - SELECT h, 1 AS level, ARRAY[id] AS breadcrumb - FROM comment h - WHERE parent_id is null - UNION ALL - SELECT hi, q.level + 1 AS level, breadcrumb || id - FROM q - JOIN comment hi - ON hi.parent_id = (q.h).id + SELECT + h, + 1 AS level, + ARRAY[id] AS breadcrumb + FROM + comment h + WHERE + parent_id IS NULL + UNION ALL + SELECT + hi, + q.level + 1 AS level, + breadcrumb || id + FROM + q + JOIN comment hi ON hi.parent_id = (q.h).id ) -SELECT (q.h).id, - (q.h).parent_id, - level, - breadcrumb::VARCHAR AS path, - text2ltree('0.' || array_to_string(breadcrumb, '.')) as ltree_path -FROM q +SELECT + (q.h).id, + (q.h).parent_id, + level, + breadcrumb::varchar AS path, + text2ltree ('0.' || array_to_string(breadcrumb, '.')) AS ltree_path +FROM + q ORDER BY - breadcrumb; + breadcrumb; -- Remove indexes and foreign key constraints, and disable triggers for faster updates -alter table comment disable trigger user; +ALTER TABLE comment DISABLE TRIGGER USER; -alter table comment drop constraint if exists comment_creator_id_fkey; -alter table comment drop constraint if exists comment_parent_id_fkey; -alter table comment drop constraint if exists comment_post_id_fkey; -alter table comment drop constraint if exists idx_comment_ap_id; +ALTER TABLE comment + DROP CONSTRAINT IF EXISTS comment_creator_id_fkey; -drop index if exists idx_comment_creator; -drop index if exists idx_comment_parent; -drop index if exists idx_comment_post; -drop index if exists idx_comment_published; +ALTER TABLE comment + DROP CONSTRAINT IF EXISTS comment_parent_id_fkey; + +ALTER TABLE comment + DROP CONSTRAINT IF EXISTS comment_post_id_fkey; + +ALTER TABLE comment + DROP CONSTRAINT IF EXISTS idx_comment_ap_id; + +DROP INDEX IF EXISTS idx_comment_creator; + +DROP INDEX IF EXISTS idx_comment_parent; + +DROP INDEX IF EXISTS idx_comment_post; + +DROP INDEX IF EXISTS idx_comment_published; -- Add the ltree column -update comment c -set path = ct.ltree_path -from comment_temp ct -where c.id = ct.id; +UPDATE + comment c +SET + path = ct.ltree_path +FROM + comment_temp ct +WHERE + c.id = ct.id; -- Update the child counts -update comment_aggregates ca set child_count = c2.child_count -from ( - select c.id, c.path, count(c2.id) as child_count from comment c - left join comment c2 on c2.path <@ c.path and c2.path != c.path - group by c.id -) as c2 -where ca.comment_id = c2.id; +UPDATE + comment_aggregates ca +SET + child_count = c2.child_count +FROM ( + SELECT + c.id, + c.path, + count(c2.id) AS child_count + FROM + comment c + LEFT JOIN comment c2 ON c2.path <@ c.path + AND c2.path != c.path +GROUP BY + c.id) AS c2 +WHERE + ca.comment_id = c2.id; -- Delete comments at a depth of > 150, otherwise the index creation below will fail -delete from comment where nlevel(path) > 150; +DELETE FROM comment +WHERE nlevel (path) > 150; -- Delete from comment where there is a missing post -delete from comment c where not exists ( - select from post p where p.id = c.post_id -); +DELETE FROM comment c +WHERE NOT EXISTS ( + SELECT + FROM + post p + WHERE + p.id = c.post_id); -- Delete from comment where there is a missing creator_id -delete from comment c where not exists ( - select from person p where p.id = c.creator_id -); +DELETE FROM comment c +WHERE NOT EXISTS ( + SELECT + FROM + person p + WHERE + p.id = c.creator_id); -- Re-enable old constraints and indexes -alter table comment add constraint "comment_creator_id_fkey" FOREIGN KEY (creator_id) REFERENCES person(id) ON UPDATE CASCADE ON DELETE CASCADE; -alter table comment add constraint "comment_post_id_fkey" FOREIGN KEY (post_id) REFERENCES post(id) ON UPDATE CASCADE ON DELETE CASCADE; -alter table comment add constraint "idx_comment_ap_id" unique (ap_id); +ALTER TABLE comment + ADD CONSTRAINT "comment_creator_id_fkey" FOREIGN KEY (creator_id) REFERENCES person (id) ON UPDATE CASCADE ON DELETE CASCADE; -create index idx_comment_creator on comment (creator_id); -create index idx_comment_post on comment (post_id); -create index idx_comment_published on comment (published desc); +ALTER TABLE comment + ADD CONSTRAINT "comment_post_id_fkey" FOREIGN KEY (post_id) REFERENCES post (id) ON UPDATE CASCADE ON DELETE CASCADE; + +ALTER TABLE comment + ADD CONSTRAINT "idx_comment_ap_id" UNIQUE (ap_id); + +CREATE INDEX idx_comment_creator ON comment (creator_id); + +CREATE INDEX idx_comment_post ON comment (post_id); + +CREATE INDEX idx_comment_published ON comment (published DESC); -- Create the index -create index idx_path_gist on comment using gist (path); +CREATE INDEX idx_path_gist ON comment USING gist (path); -- Drop the parent_id column -alter table comment drop column parent_id cascade; +ALTER TABLE comment + DROP COLUMN parent_id CASCADE; + +ALTER TABLE comment ENABLE TRIGGER USER; -alter table comment enable trigger user; diff --git a/migrations/2022-08-04-150644_add_application_email_admins/down.sql b/migrations/2022-08-04-150644_add_application_email_admins/down.sql index c515275ae..0f9228e9a 100644 --- a/migrations/2022-08-04-150644_add_application_email_admins/down.sql +++ b/migrations/2022-08-04-150644_add_application_email_admins/down.sql @@ -1 +1,3 @@ -alter table site drop column application_email_admins; +ALTER TABLE site + DROP COLUMN application_email_admins; + diff --git a/migrations/2022-08-04-150644_add_application_email_admins/up.sql b/migrations/2022-08-04-150644_add_application_email_admins/up.sql index adf8f3c11..0bad52934 100644 --- a/migrations/2022-08-04-150644_add_application_email_admins/up.sql +++ b/migrations/2022-08-04-150644_add_application_email_admins/up.sql @@ -1,2 +1,4 @@ -- Adding a field to email admins for new applications -alter table site add column application_email_admins boolean not null default false; +ALTER TABLE site + ADD COLUMN application_email_admins boolean NOT NULL DEFAULT FALSE; + diff --git a/migrations/2022-08-04-214722_add_distinguished_comment/down.sql b/migrations/2022-08-04-214722_add_distinguished_comment/down.sql index fff64498e..8af586929 100644 --- a/migrations/2022-08-04-214722_add_distinguished_comment/down.sql +++ b/migrations/2022-08-04-214722_add_distinguished_comment/down.sql @@ -1 +1,3 @@ -alter table comment drop column distinguished; +ALTER TABLE comment + DROP COLUMN distinguished; + diff --git a/migrations/2022-08-04-214722_add_distinguished_comment/up.sql b/migrations/2022-08-04-214722_add_distinguished_comment/up.sql index a23d2331f..16f416ae3 100644 --- a/migrations/2022-08-04-214722_add_distinguished_comment/up.sql +++ b/migrations/2022-08-04-214722_add_distinguished_comment/up.sql @@ -1 +1,3 @@ -alter table comment add column distinguished boolean not null default false; +ALTER TABLE comment + ADD COLUMN distinguished boolean NOT NULL DEFAULT FALSE; + diff --git a/migrations/2022-08-05-203502_add_person_post_aggregates/down.sql b/migrations/2022-08-05-203502_add_person_post_aggregates/down.sql index f4ae52633..e48e0a8db 100644 --- a/migrations/2022-08-05-203502_add_person_post_aggregates/down.sql +++ b/migrations/2022-08-05-203502_add_person_post_aggregates/down.sql @@ -1 +1,2 @@ -drop table person_post_aggregates; +DROP TABLE person_post_aggregates; + diff --git a/migrations/2022-08-05-203502_add_person_post_aggregates/up.sql b/migrations/2022-08-05-203502_add_person_post_aggregates/up.sql index 9a0a5fa5f..4fcae3b2e 100644 --- a/migrations/2022-08-05-203502_add_person_post_aggregates/up.sql +++ b/migrations/2022-08-05-203502_add_person_post_aggregates/up.sql @@ -1,11 +1,12 @@ -- This table stores the # of read comments for a person, on a post -- It can then be joined to post_aggregates to get an unread count: -- unread = post_aggregates.comments - person_post_aggregates.read_comments -create table person_post_aggregates( - id serial primary key, - person_id int references person on update cascade on delete cascade not null, - post_id int references post on update cascade on delete cascade not null, - read_comments bigint not null default 0, - published timestamp not null default now(), - unique(person_id, post_id) +CREATE TABLE person_post_aggregates ( + id serial PRIMARY KEY, + person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + read_comments bigint NOT NULL DEFAULT 0, + published timestamp NOT NULL DEFAULT now(), + UNIQUE (person_id, post_id) ); + diff --git a/migrations/2022-08-22-193848_comment-language-tags/down.sql b/migrations/2022-08-22-193848_comment-language-tags/down.sql index 7c15bfdc1..745a6b35c 100644 --- a/migrations/2022-08-22-193848_comment-language-tags/down.sql +++ b/migrations/2022-08-22-193848_comment-language-tags/down.sql @@ -1 +1,3 @@ -alter table comment drop column language_id; +ALTER TABLE comment + DROP COLUMN language_id; + diff --git a/migrations/2022-08-22-193848_comment-language-tags/up.sql b/migrations/2022-08-22-193848_comment-language-tags/up.sql index 78fe0e957..782931cb5 100644 --- a/migrations/2022-08-22-193848_comment-language-tags/up.sql +++ b/migrations/2022-08-22-193848_comment-language-tags/up.sql @@ -1 +1,4 @@ -alter table comment add column language_id integer references language not null default 0; +ALTER TABLE comment + ADD COLUMN language_id integer REFERENCES LANGUAGE NOT + NULL DEFAULT 0; + diff --git a/migrations/2022-09-07-113813_drop_ccnew_indexes_function/down.sql b/migrations/2022-09-07-113813_drop_ccnew_indexes_function/down.sql index 3fc7778a5..eede81868 100644 --- a/migrations/2022-09-07-113813_drop_ccnew_indexes_function/down.sql +++ b/migrations/2022-09-07-113813_drop_ccnew_indexes_function/down.sql @@ -1 +1,2 @@ -drop function drop_ccnew_indexes; +DROP FUNCTION drop_ccnew_indexes; + diff --git a/migrations/2022-09-07-113813_drop_ccnew_indexes_function/up.sql b/migrations/2022-09-07-113813_drop_ccnew_indexes_function/up.sql index 2a861aaff..0314b1ddc 100644 --- a/migrations/2022-09-07-113813_drop_ccnew_indexes_function/up.sql +++ b/migrations/2022-09-07-113813_drop_ccnew_indexes_function/up.sql @@ -1,13 +1,21 @@ -CREATE OR REPLACE FUNCTION drop_ccnew_indexes() RETURNS INTEGER AS $$ +CREATE OR REPLACE FUNCTION drop_ccnew_indexes () + RETURNS integer + AS $$ DECLARE -i RECORD; + i RECORD; BEGIN - FOR i IN - (SELECT relname FROM pg_class WHERE relname like '%ccnew%') - LOOP - EXECUTE 'DROP INDEX ' || i.relname; - END LOOP; + FOR i IN ( + SELECT + relname + FROM + pg_class + WHERE + relname LIKE '%ccnew%') + LOOP + EXECUTE 'DROP INDEX ' || i.relname; + END LOOP; RETURN 1; - END; -$$ LANGUAGE plpgsql; +END; +$$ +LANGUAGE plpgsql; diff --git a/migrations/2022-09-07-114618_pm-reports/down.sql b/migrations/2022-09-07-114618_pm-reports/down.sql index 1db179aff..46466d5e3 100644 --- a/migrations/2022-09-07-114618_pm-reports/down.sql +++ b/migrations/2022-09-07-114618_pm-reports/down.sql @@ -1 +1,2 @@ -drop table private_message_report; +DROP TABLE private_message_report; + diff --git a/migrations/2022-09-07-114618_pm-reports/up.sql b/migrations/2022-09-07-114618_pm-reports/up.sql index 7574f7cf4..aa168c339 100644 --- a/migrations/2022-09-07-114618_pm-reports/up.sql +++ b/migrations/2022-09-07-114618_pm-reports/up.sql @@ -1,12 +1,13 @@ -create table private_message_report ( - id serial primary key, - creator_id int references person on update cascade on delete cascade not null, -- user reporting comment - private_message_id int references private_message on update cascade on delete cascade not null, -- comment being reported - original_pm_text text not null, - reason text not null, - resolved bool not null default false, - resolver_id int references person on update cascade on delete cascade, -- user resolving report - published timestamp not null default now(), - updated timestamp null, - unique(private_message_id, creator_id) -- users should only be able to report a pm once +CREATE TABLE private_message_report ( + id serial PRIMARY KEY, + creator_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- user reporting comment + private_message_id int REFERENCES private_message ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, -- comment being reported + original_pm_text text NOT NULL, + reason text NOT NULL, + resolved bool NOT NULL DEFAULT FALSE, + resolver_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE, -- user resolving report + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL, + UNIQUE (private_message_id, creator_id) -- users should only be able to report a pm once ); + diff --git a/migrations/2022-09-08-102358_site-and-community-languages/down.sql b/migrations/2022-09-08-102358_site-and-community-languages/down.sql index eeff85b2c..4cebf5336 100644 --- a/migrations/2022-09-08-102358_site-and-community-languages/down.sql +++ b/migrations/2022-09-08-102358_site-and-community-languages/down.sql @@ -1,3 +1,6 @@ -drop table site_language; -drop table community_language; -delete from local_user_language; +DROP TABLE site_language; + +DROP TABLE community_language; + +DELETE FROM local_user_language; + diff --git a/migrations/2022-09-08-102358_site-and-community-languages/up.sql b/migrations/2022-09-08-102358_site-and-community-languages/up.sql index 7687c1b31..0f56b4782 100644 --- a/migrations/2022-09-08-102358_site-and-community-languages/up.sql +++ b/migrations/2022-09-08-102358_site-and-community-languages/up.sql @@ -1,38 +1,62 @@ -create table site_language ( - id serial primary key, - site_id int references site on update cascade on delete cascade not null, - language_id int references language on update cascade on delete cascade not null, - unique (site_id, language_id) +CREATE TABLE site_language ( + id serial PRIMARY KEY, + site_id int REFERENCES site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + language_id int REFERENCES + LANGUAGE ON + UPDATE CASCADE ON DELETE CASCADE NOT NULL, + UNIQUE (site_id, language_id) ); -create table community_language ( - id serial primary key, - community_id int references community on update cascade on delete cascade not null, - language_id int references language on update cascade on delete cascade not null, - unique (community_id, language_id) +CREATE TABLE community_language ( + id serial PRIMARY KEY, + community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + language_id int REFERENCES + LANGUAGE ON + UPDATE CASCADE ON DELETE CASCADE NOT NULL, + UNIQUE (community_id, language_id) ); -- update existing users, sites and communities to have all languages enabled -do $$ - declare - xid integer; -begin - for xid in select id from local_user - loop - insert into local_user_language (local_user_id, language_id) - (select xid, language.id as lid from language); - end loop; - - for xid in select id from site - loop - insert into site_language (site_id, language_id) - (select xid, language.id as lid from language); - end loop; - - for xid in select id from community - loop - insert into community_language (community_id, language_id) - (select xid, language.id as lid from language); - end loop; -end; +DO $$ +DECLARE + xid integer; +BEGIN + FOR xid IN + SELECT + id + FROM + local_user LOOP + INSERT INTO local_user_language (local_user_id, language_id) ( + SELECT + xid, + language.id AS lid + FROM + LANGUAGE); + END LOOP; + FOR xid IN + SELECT + id + FROM + site LOOP + INSERT INTO site_language (site_id, language_id) ( + SELECT + xid, + language.id AS lid + FROM + LANGUAGE); + END LOOP; + FOR xid IN + SELECT + id + FROM + community LOOP + INSERT INTO community_language (community_id, language_id) ( + SELECT + xid, + language.id AS lid + FROM + LANGUAGE); + END LOOP; +END; $$; + diff --git a/migrations/2022-09-24-161829_remove_table_aliases/down.sql b/migrations/2022-09-24-161829_remove_table_aliases/down.sql index 39b439a0a..7aac082ba 100644 --- a/migrations/2022-09-24-161829_remove_table_aliases/down.sql +++ b/migrations/2022-09-24-161829_remove_table_aliases/down.sql @@ -1,2 +1,12 @@ -create view person_alias_1 as select * from person; -create view person_alias_2 as select * from person; +CREATE VIEW person_alias_1 AS +SELECT + * +FROM + person; + +CREATE VIEW person_alias_2 AS +SELECT + * +FROM + person; + diff --git a/migrations/2022-09-24-161829_remove_table_aliases/up.sql b/migrations/2022-09-24-161829_remove_table_aliases/up.sql index 36eabecab..f4ac9c771 100644 --- a/migrations/2022-09-24-161829_remove_table_aliases/up.sql +++ b/migrations/2022-09-24-161829_remove_table_aliases/up.sql @@ -1,2 +1,3 @@ -- Drop the alias views -drop view person_alias_1, person_alias_2; +DROP VIEW person_alias_1, person_alias_2; + diff --git a/migrations/2022-10-06-183632_move_blocklist_to_db/down.sql b/migrations/2022-10-06-183632_move_blocklist_to_db/down.sql index 3ca49b548..af95b8773 100644 --- a/migrations/2022-10-06-183632_move_blocklist_to_db/down.sql +++ b/migrations/2022-10-06-183632_move_blocklist_to_db/down.sql @@ -1,63 +1,78 @@ -- Add back site columns -alter table site - add column enable_downvotes boolean default true not null, - add column open_registration boolean default true not null, - add column enable_nsfw boolean default true not null, - add column community_creation_admin_only boolean default false not null, - add column require_email_verification boolean default false not null, - add column require_application boolean default true not null, - add column application_question text default 'to verify that you are human, please explain why you want to create an account on this site'::text, - add column private_instance boolean default false not null, - add column default_theme text default 'browser'::text not null, - add column default_post_listing_type text default 'Local'::text not null, - add column legal_information text, - add column hide_modlog_mod_names boolean default true not null, - add column application_email_admins boolean default false not null; +ALTER TABLE site + ADD COLUMN enable_downvotes boolean DEFAULT TRUE NOT NULL, + ADD COLUMN open_registration boolean DEFAULT TRUE NOT NULL, + ADD COLUMN enable_nsfw boolean DEFAULT TRUE NOT NULL, + ADD COLUMN community_creation_admin_only boolean DEFAULT FALSE NOT NULL, + ADD COLUMN require_email_verification boolean DEFAULT FALSE NOT NULL, + ADD COLUMN require_application boolean DEFAULT TRUE NOT NULL, + ADD COLUMN application_question text DEFAULT 'to verify that you are human, please explain why you want to create an account on this site'::text, + ADD COLUMN private_instance boolean DEFAULT FALSE NOT NULL, + ADD COLUMN default_theme text DEFAULT 'browser'::text NOT NULL, + ADD COLUMN default_post_listing_type text DEFAULT 'Local'::text NOT NULL, + ADD COLUMN legal_information text, + ADD COLUMN hide_modlog_mod_names boolean DEFAULT TRUE NOT NULL, + ADD COLUMN application_email_admins boolean DEFAULT FALSE NOT NULL; -- Insert the data back from local_site -update site set - enable_downvotes = ls.enable_downvotes, - open_registration = ls.open_registration, - enable_nsfw = ls.enable_nsfw, - community_creation_admin_only = ls.community_creation_admin_only, - require_email_verification = ls.require_email_verification, - require_application = ls.require_application, - application_question = ls.application_question, - private_instance = ls.private_instance, - default_theme = ls.default_theme, - default_post_listing_type = ls.default_post_listing_type, - legal_information = ls.legal_information, - hide_modlog_mod_names = ls.hide_modlog_mod_names, - application_email_admins = ls.application_email_admins, - published = ls.published, - updated = ls.updated -from (select - site_id, - enable_downvotes, - open_registration, - enable_nsfw, - community_creation_admin_only, - require_email_verification, - require_application, - application_question, - private_instance, - default_theme, - default_post_listing_type, - legal_information, - hide_modlog_mod_names, - application_email_admins, - published, - updated -from local_site) as ls -where site.id = ls.site_id; +UPDATE + site +SET + enable_downvotes = ls.enable_downvotes, + open_registration = ls.open_registration, + enable_nsfw = ls.enable_nsfw, + community_creation_admin_only = ls.community_creation_admin_only, + require_email_verification = ls.require_email_verification, + require_application = ls.require_application, + application_question = ls.application_question, + private_instance = ls.private_instance, + default_theme = ls.default_theme, + default_post_listing_type = ls.default_post_listing_type, + legal_information = ls.legal_information, + hide_modlog_mod_names = ls.hide_modlog_mod_names, + application_email_admins = ls.application_email_admins, + published = ls.published, + updated = ls.updated +FROM ( + SELECT + site_id, + enable_downvotes, + open_registration, + enable_nsfw, + community_creation_admin_only, + require_email_verification, + require_application, + application_question, + private_instance, + default_theme, + default_post_listing_type, + legal_information, + hide_modlog_mod_names, + application_email_admins, + published, + updated + FROM + local_site) AS ls +WHERE + site.id = ls.site_id; -- drop instance columns -alter table site drop column instance_id; -alter table person drop column instance_id; -alter table community drop column instance_id; +ALTER TABLE site + DROP COLUMN instance_id; + +ALTER TABLE person + DROP COLUMN instance_id; + +ALTER TABLE community + DROP COLUMN instance_id; + +DROP TABLE local_site_rate_limit; + +DROP TABLE local_site; + +DROP TABLE federation_allowlist; + +DROP TABLE federation_blocklist; + +DROP TABLE instance; -drop table local_site_rate_limit; -drop table local_site; -drop table federation_allowlist; -drop table federation_blocklist; -drop table instance; diff --git a/migrations/2022-10-06-183632_move_blocklist_to_db/up.sql b/migrations/2022-10-06-183632_move_blocklist_to_db/up.sql index e814ce27a..3b97daccd 100644 --- a/migrations/2022-10-06-183632_move_blocklist_to_db/up.sql +++ b/migrations/2022-10-06-183632_move_blocklist_to_db/up.sql @@ -1,186 +1,202 @@ -- Create an instance table -- Holds any connected or unconnected domain -create table instance ( - id serial primary key, - domain varchar(255) not null unique, - published timestamp not null default now(), - updated timestamp null +CREATE TABLE instance ( + id serial PRIMARY KEY, + domain varchar(255) NOT NULL UNIQUE, + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL ); -- Insert all the domains to the instance table -insert into instance (domain) -select distinct substring(p.actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') from ( - select actor_id from site - union - select actor_id from person - union - select actor_id from community -) as p; +INSERT INTO instance (DOMAIN) +SELECT DISTINCT + substring(p.actor_id FROM '(?:.*://)?(?:www\.)?([^/?]*)') +FROM ( + SELECT + actor_id + FROM + site + UNION + SELECT + actor_id + FROM + person + UNION + SELECT + actor_id + FROM + community) AS p; -- Alter site, person, and community tables to reference the instance table. -alter table site add column -instance_id int references instance on update cascade on delete cascade; +ALTER TABLE site + ADD COLUMN instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE; -alter table person add column -instance_id int references instance on update cascade on delete cascade; +ALTER TABLE person + ADD COLUMN instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE; -alter table community add column -instance_id int references instance on update cascade on delete cascade; +ALTER TABLE community + ADD COLUMN instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE; -- Add those columns -update site set instance_id = i.id -from instance i -where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; +UPDATE + site +SET + instance_id = i.id +FROM + instance i +WHERE + substring(actor_id FROM '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; -update person set instance_id = i.id -from instance i -where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; +UPDATE + person +SET + instance_id = i.id +FROM + instance i +WHERE + substring(actor_id FROM '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; -update community set instance_id = i.id -from instance i -where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; +UPDATE + community +SET + instance_id = i.id +FROM + instance i +WHERE + substring(actor_id FROM '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain; -- Make those columns unique not null now -alter table site alter column instance_id set not null; -alter table site add constraint idx_site_instance_unique unique (instance_id); +ALTER TABLE site + ALTER COLUMN instance_id SET NOT NULL; -alter table person alter column instance_id set not null; -alter table community alter column instance_id set not null; +ALTER TABLE site + ADD CONSTRAINT idx_site_instance_unique UNIQUE (instance_id); + +ALTER TABLE person + ALTER COLUMN instance_id SET NOT NULL; + +ALTER TABLE community + ALTER COLUMN instance_id SET NOT NULL; -- Create allowlist and blocklist tables -create table federation_allowlist ( - id serial primary key, - instance_id int references instance on update cascade on delete cascade not null unique, - published timestamp not null default now(), - updated timestamp null +CREATE TABLE federation_allowlist ( + id serial PRIMARY KEY, + instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE NOT NULL UNIQUE, + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL ); -create table federation_blocklist ( - id serial primary key, - instance_id int references instance on update cascade on delete cascade not null unique, - published timestamp not null default now(), - updated timestamp null +CREATE TABLE federation_blocklist ( + id serial PRIMARY KEY, + instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE NOT NULL UNIQUE, + published timestamp NOT NULL DEFAULT now(), + updated timestamp NULL ); -- Move all the extra site settings-type columns to a local_site table -- Add a lot of other fields currently in the lemmy.hjson -create table local_site ( - id serial primary key, - site_id int references site on update cascade on delete cascade not null unique, - - -- Site table fields - site_setup boolean default false not null, - enable_downvotes boolean default true not null, - open_registration boolean default true not null, - enable_nsfw boolean default true not null, - community_creation_admin_only boolean default false not null, - require_email_verification boolean default false not null, - require_application boolean default true not null, - application_question text default 'to verify that you are human, please explain why you want to create an account on this site'::text, - private_instance boolean default false not null, - default_theme text default 'browser'::text not null, - default_post_listing_type text default 'Local'::text not null, - legal_information text, - hide_modlog_mod_names boolean default true not null, - application_email_admins boolean default false not null, - - -- Fields from lemmy.hjson - slur_filter_regex text, - actor_name_max_length int default 20 not null, - federation_enabled boolean default true not null, - federation_debug boolean default false not null, - federation_strict_allowlist boolean default true not null, - federation_http_fetch_retry_limit int default 25 not null, - federation_worker_count int default 64 not null, - captcha_enabled boolean default false not null, - captcha_difficulty varchar(255) default 'medium' not null, - - -- Time fields - published timestamp without time zone default now() not null, - updated timestamp without time zone +CREATE TABLE local_site ( + id serial PRIMARY KEY, + site_id int REFERENCES site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL UNIQUE, + -- Site table fields + site_setup boolean DEFAULT FALSE NOT NULL, + enable_downvotes boolean DEFAULT TRUE NOT NULL, + open_registration boolean DEFAULT TRUE NOT NULL, + enable_nsfw boolean DEFAULT TRUE NOT NULL, + community_creation_admin_only boolean DEFAULT FALSE NOT NULL, + require_email_verification boolean DEFAULT FALSE NOT NULL, + require_application boolean DEFAULT TRUE NOT NULL, + application_question text DEFAULT 'to verify that you are human, please explain why you want to create an account on this site' ::text, + private_instance boolean DEFAULT FALSE NOT NULL, + default_theme text DEFAULT 'browser' ::text NOT NULL, + default_post_listing_type text DEFAULT 'Local' ::text NOT NULL, + legal_information text, + hide_modlog_mod_names boolean DEFAULT TRUE NOT NULL, + application_email_admins boolean DEFAULT FALSE NOT NULL, + -- Fields from lemmy.hjson + slur_filter_regex text, + actor_name_max_length int DEFAULT 20 NOT NULL, + federation_enabled boolean DEFAULT TRUE NOT NULL, + federation_debug boolean DEFAULT FALSE NOT NULL, + federation_strict_allowlist boolean DEFAULT TRUE NOT NULL, + federation_http_fetch_retry_limit int DEFAULT 25 NOT NULL, + federation_worker_count int DEFAULT 64 NOT NULL, + captcha_enabled boolean DEFAULT FALSE NOT NULL, + captcha_difficulty varchar(255) DEFAULT 'medium' NOT NULL, + -- Time fields + published timestamp without time zone DEFAULT now() NOT NULL, + updated timestamp without time zone ); -- local_site_rate_limit is its own table, so as to not go over 32 columns, and force diesel to use the 64-column-tables feature -create table local_site_rate_limit ( - id serial primary key, - local_site_id int references local_site on update cascade on delete cascade not null unique, - message int default 180 not null, - message_per_second int default 60 not null, - post int default 6 not null, - post_per_second int default 600 not null, - register int default 3 not null, - register_per_second int default 3600 not null, - image int default 6 not null, - image_per_second int default 3600 not null, - comment int default 6 not null, - comment_per_second int default 600 not null, - search int default 60 not null, - search_per_second int default 600 not null, - published timestamp without time zone default now() not null, - updated timestamp without time zone +CREATE TABLE local_site_rate_limit ( + id serial PRIMARY KEY, + local_site_id int REFERENCES local_site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL UNIQUE, + message int DEFAULT 180 NOT NULL, + message_per_second int DEFAULT 60 NOT NULL, + post int DEFAULT 6 NOT NULL, + post_per_second int DEFAULT 600 NOT NULL, + register int DEFAULT 3 NOT NULL, + register_per_second int DEFAULT 3600 NOT NULL, + image int DEFAULT 6 NOT NULL, + image_per_second int DEFAULT 3600 NOT NULL, + comment int DEFAULT 6 NOT NULL, + comment_per_second int DEFAULT 600 NOT NULL, + search int DEFAULT 60 NOT NULL, + search_per_second int DEFAULT 600 NOT NULL, + published timestamp without time zone DEFAULT now() NOT NULL, + updated timestamp without time zone ); -- Insert the data into local_site -insert into local_site ( - site_id, - site_setup, - enable_downvotes, - open_registration, - enable_nsfw, - community_creation_admin_only, - require_email_verification, - require_application, - application_question, - private_instance, - default_theme, - default_post_listing_type, - legal_information, - hide_modlog_mod_names, - application_email_admins, - published, - updated -) -select - id, - true, -- Assume site if setup if there's already a site row - enable_downvotes, - open_registration, - enable_nsfw, - community_creation_admin_only, - require_email_verification, - require_application, - application_question, - private_instance, - default_theme, - default_post_listing_type, - legal_information, - hide_modlog_mod_names, - application_email_admins, - published, - updated -from site -order by id limit 1; +INSERT INTO local_site (site_id, site_setup, enable_downvotes, open_registration, enable_nsfw, community_creation_admin_only, require_email_verification, require_application, application_question, private_instance, default_theme, default_post_listing_type, legal_information, hide_modlog_mod_names, application_email_admins, published, updated) +SELECT + id, + TRUE, -- Assume site if setup if there's already a site row + enable_downvotes, + open_registration, + enable_nsfw, + community_creation_admin_only, + require_email_verification, + require_application, + application_question, + private_instance, + default_theme, + default_post_listing_type, + legal_information, + hide_modlog_mod_names, + application_email_admins, + published, + updated +FROM + site +ORDER BY + id +LIMIT 1; -- Default here -insert into local_site_rate_limit ( - local_site_id -) -select id from local_site -order by id limit 1; +INSERT INTO local_site_rate_limit (local_site_id) +SELECT + id +FROM + local_site +ORDER BY + id +LIMIT 1; -- Drop all those columns from site -alter table site - drop column enable_downvotes, - drop column open_registration, - drop column enable_nsfw, - drop column community_creation_admin_only, - drop column require_email_verification, - drop column require_application, - drop column application_question, - drop column private_instance, - drop column default_theme, - drop column default_post_listing_type, - drop column legal_information, - drop column hide_modlog_mod_names, - drop column application_email_admins; +ALTER TABLE site + DROP COLUMN enable_downvotes, + DROP COLUMN open_registration, + DROP COLUMN enable_nsfw, + DROP COLUMN community_creation_admin_only, + DROP COLUMN require_email_verification, + DROP COLUMN require_application, + DROP COLUMN application_question, + DROP COLUMN private_instance, + DROP COLUMN default_theme, + DROP COLUMN default_post_listing_type, + DROP COLUMN legal_information, + DROP COLUMN hide_modlog_mod_names, + DROP COLUMN application_email_admins; diff --git a/migrations/2022-11-13-181529_create_taglines/down.sql b/migrations/2022-11-13-181529_create_taglines/down.sql index 4867e5f15..5471b4b73 100644 --- a/migrations/2022-11-13-181529_create_taglines/down.sql +++ b/migrations/2022-11-13-181529_create_taglines/down.sql @@ -1 +1,2 @@ -drop table tagline; \ No newline at end of file +DROP TABLE tagline; + diff --git a/migrations/2022-11-13-181529_create_taglines/up.sql b/migrations/2022-11-13-181529_create_taglines/up.sql index ff88cf4c2..ed4daa63a 100644 --- a/migrations/2022-11-13-181529_create_taglines/up.sql +++ b/migrations/2022-11-13-181529_create_taglines/up.sql @@ -1,7 +1,8 @@ -create table tagline ( - id serial primary key, - local_site_id int references local_site on update cascade on delete cascade not null, - content text not null, - published timestamp without time zone default now() not null, - updated timestamp without time zone -); \ No newline at end of file +CREATE TABLE tagline ( + id serial PRIMARY KEY, + local_site_id int REFERENCES local_site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + content text NOT NULL, + published timestamp without time zone DEFAULT now() NOT NULL, + updated timestamp without time zone +); + diff --git a/migrations/2022-11-20-032430_sticky_local/down.sql b/migrations/2022-11-20-032430_sticky_local/down.sql index 46a2b6a9b..767c9aa7f 100644 --- a/migrations/2022-11-20-032430_sticky_local/down.sql +++ b/migrations/2022-11-20-032430_sticky_local/down.sql @@ -1,47 +1,67 @@ - DROP TRIGGER IF EXISTS post_aggregates_featured_local ON post; + DROP TRIGGER IF EXISTS post_aggregates_featured_community ON post; -drop function post_aggregates_featured_community; -drop function post_aggregates_featured_local; +DROP FUNCTION post_aggregates_featured_community; -alter table post ADD stickied boolean NOT NULL DEFAULT false; -Update post -set stickied = featured_community; -alter table post DROP COLUMN featured_community; -alter table post DROP COLUMN featured_local; +DROP FUNCTION post_aggregates_featured_local; -alter table post_aggregates ADD stickied boolean NOT NULL DEFAULT false; -Update post_aggregates -set stickied = featured_community; -alter table post_aggregates DROP COLUMN featured_community; -alter table post_aggregates DROP COLUMN featured_local; +ALTER TABLE post + ADD stickied boolean NOT NULL DEFAULT FALSE; -alter table mod_feature_post -rename column featured TO stickied; +UPDATE + post +SET + stickied = featured_community; -alter table mod_feature_post -DROP COLUMN is_featured_community; +ALTER TABLE post + DROP COLUMN featured_community; -alter table mod_feature_post -alter column stickied DROP NOT NULL; +ALTER TABLE post + DROP COLUMN featured_local; -alter table mod_feature_post -Rename To mod_sticky_post; +ALTER TABLE post_aggregates + ADD stickied boolean NOT NULL DEFAULT FALSE; -create function post_aggregates_stickied() -returns trigger language plpgsql -as $$ -begin - update post_aggregates pa - set stickied = NEW.stickied - where pa.post_id = NEW.id; +UPDATE + post_aggregates +SET + stickied = featured_community; - return null; -end $$; +ALTER TABLE post_aggregates + DROP COLUMN featured_community; + +ALTER TABLE post_aggregates + DROP COLUMN featured_local; + +ALTER TABLE mod_feature_post RENAME COLUMN featured TO stickied; + +ALTER TABLE mod_feature_post + DROP COLUMN is_featured_community; + +ALTER TABLE mod_feature_post + ALTER COLUMN stickied DROP NOT NULL; + +ALTER TABLE mod_feature_post RENAME TO mod_sticky_post; + +CREATE FUNCTION post_aggregates_stickied () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + post_aggregates pa + SET + stickied = NEW.stickied + WHERE + pa.post_id = NEW.id; + RETURN NULL; +END +$$; + +CREATE TRIGGER post_aggregates_stickied + AFTER UPDATE ON post + FOR EACH ROW + WHEN (OLD.stickied IS DISTINCT FROM NEW.stickied) + EXECUTE PROCEDURE post_aggregates_stickied (); -create trigger post_aggregates_stickied -after update on post -for each row -when (OLD.stickied is distinct from NEW.stickied) -execute procedure post_aggregates_stickied(); \ No newline at end of file diff --git a/migrations/2022-11-20-032430_sticky_local/up.sql b/migrations/2022-11-20-032430_sticky_local/up.sql index 202c4c4b0..0411256d8 100644 --- a/migrations/2022-11-20-032430_sticky_local/up.sql +++ b/migrations/2022-11-20-032430_sticky_local/up.sql @@ -1,63 +1,84 @@ - DROP TRIGGER IF EXISTS post_aggregates_stickied ON post; -drop function - post_aggregates_stickied; +DROP FUNCTION post_aggregates_stickied; -alter table post ADD featured_community boolean NOT NULL DEFAULT false; -alter table post ADD featured_local boolean NOT NULL DEFAULT false; -update post -set featured_community = stickied; -alter table post DROP COLUMN stickied; +ALTER TABLE post + ADD featured_community boolean NOT NULL DEFAULT FALSE; -alter table post_aggregates ADD featured_community boolean NOT NULL DEFAULT false; -alter table post_aggregates ADD featured_local boolean NOT NULL DEFAULT false; -update post_aggregates -set featured_community = stickied; -alter table post_aggregates DROP COLUMN stickied; +ALTER TABLE post + ADD featured_local boolean NOT NULL DEFAULT FALSE; -alter table mod_sticky_post -rename column stickied TO featured; +UPDATE + post +SET + featured_community = stickied; -alter table mod_sticky_post -alter column featured SET NOT NULL; +ALTER TABLE post + DROP COLUMN stickied; -alter table mod_sticky_post -ADD is_featured_community boolean NOT NULL DEFAULT true; +ALTER TABLE post_aggregates + ADD featured_community boolean NOT NULL DEFAULT FALSE; -alter table mod_sticky_post -Rename To mod_feature_post; +ALTER TABLE post_aggregates + ADD featured_local boolean NOT NULL DEFAULT FALSE; -create function post_aggregates_featured_community() -returns trigger language plpgsql -as $$ -begin - update post_aggregates pa - set featured_community = NEW.featured_community - where pa.post_id = NEW.id; - return null; -end $$; +UPDATE + post_aggregates +SET + featured_community = stickied; -create function post_aggregates_featured_local() -returns trigger language plpgsql -as $$ -begin - update post_aggregates pa - set featured_local = NEW.featured_local - where pa.post_id = NEW.id; - return null; -end $$; +ALTER TABLE post_aggregates + DROP COLUMN stickied; + +ALTER TABLE mod_sticky_post RENAME COLUMN stickied TO featured; + +ALTER TABLE mod_sticky_post + ALTER COLUMN featured SET NOT NULL; + +ALTER TABLE mod_sticky_post + ADD is_featured_community boolean NOT NULL DEFAULT TRUE; + +ALTER TABLE mod_sticky_post RENAME TO mod_feature_post; + +CREATE FUNCTION post_aggregates_featured_community () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + post_aggregates pa + SET + featured_community = NEW.featured_community + WHERE + pa.post_id = NEW.id; + RETURN NULL; +END +$$; + +CREATE FUNCTION post_aggregates_featured_local () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + UPDATE + post_aggregates pa + SET + featured_local = NEW.featured_local + WHERE + pa.post_id = NEW.id; + RETURN NULL; +END +$$; CREATE TRIGGER post_aggregates_featured_community - AFTER UPDATE - ON public.post + AFTER UPDATE ON public.post FOR EACH ROW WHEN (old.featured_community IS DISTINCT FROM new.featured_community) - EXECUTE FUNCTION public.post_aggregates_featured_community(); + EXECUTE FUNCTION public.post_aggregates_featured_community (); CREATE TRIGGER post_aggregates_featured_local - AFTER UPDATE - ON public.post + AFTER UPDATE ON public.post FOR EACH ROW WHEN (old.featured_local IS DISTINCT FROM new.featured_local) - EXECUTE FUNCTION public.post_aggregates_featured_local(); \ No newline at end of file + EXECUTE FUNCTION public.post_aggregates_featured_local (); + diff --git a/migrations/2022-11-21-143249_remove-federation-settings/down.sql b/migrations/2022-11-21-143249_remove-federation-settings/down.sql index 51452e195..066775ea9 100644 --- a/migrations/2022-11-21-143249_remove-federation-settings/down.sql +++ b/migrations/2022-11-21-143249_remove-federation-settings/down.sql @@ -1,2 +1,6 @@ -alter table local_site add column federation_strict_allowlist bool default true not null; -alter table local_site add column federation_http_fetch_retry_limit int not null default 25; +ALTER TABLE local_site + ADD COLUMN federation_strict_allowlist bool DEFAULT TRUE NOT NULL; + +ALTER TABLE local_site + ADD COLUMN federation_http_fetch_retry_limit int NOT NULL DEFAULT 25; + diff --git a/migrations/2022-11-21-143249_remove-federation-settings/up.sql b/migrations/2022-11-21-143249_remove-federation-settings/up.sql index e17563042..6b2b35936 100644 --- a/migrations/2022-11-21-143249_remove-federation-settings/up.sql +++ b/migrations/2022-11-21-143249_remove-federation-settings/up.sql @@ -1,2 +1,6 @@ -alter table local_site drop column federation_strict_allowlist; -alter table local_site drop column federation_http_fetch_retry_limit; +ALTER TABLE local_site + DROP COLUMN federation_strict_allowlist; + +ALTER TABLE local_site + DROP COLUMN federation_http_fetch_retry_limit; + diff --git a/migrations/2022-11-21-204256_user-following/down.sql b/migrations/2022-11-21-204256_user-following/down.sql index 10118ba98..1803d4d69 100644 --- a/migrations/2022-11-21-204256_user-following/down.sql +++ b/migrations/2022-11-21-204256_user-following/down.sql @@ -1,3 +1,5 @@ -drop table person_follower; +DROP TABLE person_follower; + +ALTER TABLE community_follower + ALTER COLUMN pending DROP NOT NULL; -alter table community_follower alter column pending drop not null; diff --git a/migrations/2022-11-21-204256_user-following/up.sql b/migrations/2022-11-21-204256_user-following/up.sql index 0ef6e8be7..26456b84e 100644 --- a/migrations/2022-11-21-204256_user-following/up.sql +++ b/migrations/2022-11-21-204256_user-following/up.sql @@ -1,12 +1,20 @@ -- create user follower table with two references to persons -create table person_follower ( - id serial primary key, - person_id int references person on update cascade on delete cascade not null, - follower_id int references person on update cascade on delete cascade not null, - published timestamp not null default now(), - pending boolean not null, - unique (follower_id, person_id) +CREATE TABLE person_follower ( + id serial PRIMARY KEY, + person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + follower_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + published timestamp NOT NULL DEFAULT now(), + pending boolean NOT NULL, + UNIQUE (follower_id, person_id) ); -update community_follower set pending = false where pending is null; -alter table community_follower alter column pending set not null; +UPDATE + community_follower +SET + pending = FALSE +WHERE + pending IS NULL; + +ALTER TABLE community_follower + ALTER COLUMN pending SET NOT NULL; + diff --git a/migrations/2022-12-05-110642_registration_mode/down.sql b/migrations/2022-12-05-110642_registration_mode/down.sql index 25bb36c0c..9b118ecdc 100644 --- a/migrations/2022-12-05-110642_registration_mode/down.sql +++ b/migrations/2022-12-05-110642_registration_mode/down.sql @@ -1,31 +1,48 @@ -- add back old registration columns -alter table local_site add column open_registration boolean not null default true; -alter table local_site add column require_application boolean not null default true; +ALTER TABLE local_site + ADD COLUMN open_registration boolean NOT NULL DEFAULT TRUE; + +ALTER TABLE local_site + ADD COLUMN require_application boolean NOT NULL DEFAULT TRUE; -- regenerate their values -with subquery as ( - select registration_mode, - case - when registration_mode='closed' then false - else true - end - from local_site -) -update local_site -set open_registration = subquery.case -from subquery; -with subquery as ( - select registration_mode, - case - when registration_mode='open' then false - else true - end - from local_site -) -update local_site -set require_application = subquery.case -from subquery; +WITH subquery AS ( + SELECT + registration_mode, + CASE WHEN registration_mode = 'closed' THEN + FALSE + ELSE + TRUE + END + FROM + local_site) +UPDATE + local_site +SET + open_registration = subquery.case +FROM + subquery; + +WITH subquery AS ( + SELECT + registration_mode, + CASE WHEN registration_mode = 'open' THEN + FALSE + ELSE + TRUE + END + FROM + local_site) +UPDATE + local_site +SET + require_application = subquery.case +FROM + subquery; -- drop new column and type -alter table local_site drop column registration_mode; -drop type registration_mode_enum; \ No newline at end of file +ALTER TABLE local_site + DROP COLUMN registration_mode; + +DROP TYPE registration_mode_enum; + diff --git a/migrations/2022-12-05-110642_registration_mode/up.sql b/migrations/2022-12-05-110642_registration_mode/up.sql index 34515e2cb..7f4d45ff8 100644 --- a/migrations/2022-12-05-110642_registration_mode/up.sql +++ b/migrations/2022-12-05-110642_registration_mode/up.sql @@ -1,25 +1,40 @@ -- create enum for registration modes -create type registration_mode_enum as enum - ('closed', 'require_application', 'open'); +CREATE TYPE registration_mode_enum AS enum ( + 'closed', + 'require_application', + 'open' +); -- use this enum for registration mode setting -alter table local_site add column - registration_mode registration_mode_enum not null default 'require_application'; +ALTER TABLE local_site + ADD COLUMN registration_mode registration_mode_enum NOT NULL DEFAULT 'require_application'; -- generate registration mode value from previous settings -with subquery as ( - select open_registration, require_application, - case - when open_registration=false then 'closed'::registration_mode_enum - when open_registration=true and require_application=true then 'require_application' - else 'open' - end - from local_site -) -update local_site -set registration_mode = subquery.case -from subquery; +WITH subquery AS ( + SELECT + open_registration, + require_application, + CASE WHEN open_registration = FALSE THEN + 'closed'::registration_mode_enum + WHEN open_registration = TRUE + AND require_application = TRUE THEN + 'require_application' + ELSE + 'open' + END + FROM + local_site) +UPDATE + local_site +SET + registration_mode = subquery.case +FROM + subquery; -- drop old registration settings -alter table local_site drop column open_registration; -alter table local_site drop column require_application; +ALTER TABLE local_site + DROP COLUMN open_registration; + +ALTER TABLE local_site + DROP COLUMN require_application; + diff --git a/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/down.sql b/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/down.sql index d91843e19..9064ea760 100644 --- a/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/down.sql +++ b/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/down.sql @@ -1,22 +1,16 @@ -- Drop the new indexes -drop index idx_post_aggregates_featured_local_newest_comment_time, - idx_post_aggregates_featured_community_newest_comment_time, - idx_post_aggregates_featured_local_comments, - idx_post_aggregates_featured_community_comments, - idx_post_aggregates_featured_local_hot, - idx_post_aggregates_featured_community_hot, - idx_post_aggregates_featured_local_active, - idx_post_aggregates_featured_community_active, - idx_post_aggregates_featured_local_score, - idx_post_aggregates_featured_community_score, - idx_post_aggregates_featured_local_published, - idx_post_aggregates_featured_community_published; +DROP INDEX idx_post_aggregates_featured_local_newest_comment_time, idx_post_aggregates_featured_community_newest_comment_time, idx_post_aggregates_featured_local_comments, idx_post_aggregates_featured_community_comments, idx_post_aggregates_featured_local_hot, idx_post_aggregates_featured_community_hot, idx_post_aggregates_featured_local_active, idx_post_aggregates_featured_community_active, idx_post_aggregates_featured_local_score, idx_post_aggregates_featured_community_score, idx_post_aggregates_featured_local_published, idx_post_aggregates_featured_community_published; -- Create the old indexes -create index idx_post_aggregates_newest_comment_time on post_aggregates (newest_comment_time desc); -create index idx_post_aggregates_comments on post_aggregates (comments desc); -create index idx_post_aggregates_hot on post_aggregates (hot_rank(score, published) desc, published desc); -create index idx_post_aggregates_active on post_aggregates (hot_rank(score, newest_comment_time) desc, newest_comment_time desc); -create index idx_post_aggregates_score on post_aggregates (score desc); -create index idx_post_aggregates_published on post_aggregates (published desc); +CREATE INDEX idx_post_aggregates_newest_comment_time ON post_aggregates (newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_comments ON post_aggregates (comments DESC); + +CREATE INDEX idx_post_aggregates_hot ON post_aggregates (hot_rank (score, published) DESC, published DESC); + +CREATE INDEX idx_post_aggregates_active ON post_aggregates (hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_score ON post_aggregates (score DESC); + +CREATE INDEX idx_post_aggregates_published ON post_aggregates (published DESC); diff --git a/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/up.sql b/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/up.sql index 881089293..29f571ccd 100644 --- a/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/up.sql +++ b/migrations/2023-01-17-165819_cleanup_post_aggregates_indexes/up.sql @@ -1,30 +1,30 @@ -- Drop the old indexes -drop index idx_post_aggregates_newest_comment_time, - idx_post_aggregates_comments, - idx_post_aggregates_hot, - idx_post_aggregates_active, - idx_post_aggregates_score, - idx_post_aggregates_published; +DROP INDEX idx_post_aggregates_newest_comment_time, idx_post_aggregates_comments, idx_post_aggregates_hot, idx_post_aggregates_active, idx_post_aggregates_score, idx_post_aggregates_published; --- All of the post fetching queries now start with either +-- All of the post fetching queries now start with either -- featured_local desc, or featured_community desc, then the other sorts. -- So you now need to double these indexes +CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time ON post_aggregates (featured_local DESC, newest_comment_time DESC); -create index idx_post_aggregates_featured_local_newest_comment_time on post_aggregates (featured_local desc, newest_comment_time desc); -create index idx_post_aggregates_featured_community_newest_comment_time on post_aggregates (featured_community desc, newest_comment_time desc); +CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time ON post_aggregates (featured_community DESC, newest_comment_time DESC); -create index idx_post_aggregates_featured_local_comments on post_aggregates (featured_local desc, comments desc); -create index idx_post_aggregates_featured_community_comments on post_aggregates (featured_community desc, comments desc); +CREATE INDEX idx_post_aggregates_featured_local_comments ON post_aggregates (featured_local DESC, comments DESC); -create index idx_post_aggregates_featured_local_hot on post_aggregates (featured_local desc, hot_rank(score, published) desc, published desc); -create index idx_post_aggregates_featured_community_hot on post_aggregates (featured_community desc, hot_rank(score, published) desc, published desc); +CREATE INDEX idx_post_aggregates_featured_community_comments ON post_aggregates (featured_community DESC, comments DESC); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank(score, newest_comment_time) desc, newest_comment_time desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank(score, newest_comment_time) desc, newest_comment_time desc); +CREATE INDEX idx_post_aggregates_featured_local_hot ON post_aggregates (featured_local DESC, hot_rank (score, published) DESC, published DESC); -create index idx_post_aggregates_featured_local_score on post_aggregates (featured_local desc, score desc); -create index idx_post_aggregates_featured_community_score on post_aggregates (featured_community desc, score desc); +CREATE INDEX idx_post_aggregates_featured_community_hot ON post_aggregates (featured_community DESC, hot_rank (score, published) DESC, published DESC); -create index idx_post_aggregates_featured_local_published on post_aggregates (featured_local desc, published desc); -create index idx_post_aggregates_featured_community_published on post_aggregates (featured_community desc, published desc); +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_featured_local_score ON post_aggregates (featured_local DESC, score DESC); + +CREATE INDEX idx_post_aggregates_featured_community_score ON post_aggregates (featured_community DESC, score DESC); + +CREATE INDEX idx_post_aggregates_featured_local_published ON post_aggregates (featured_local DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_community_published ON post_aggregates (featured_community DESC, published DESC); diff --git a/migrations/2023-02-01-012747_fix_active_index/down.sql b/migrations/2023-02-01-012747_fix_active_index/down.sql index 356e3b8c4..20be3105b 100644 --- a/migrations/2023-02-01-012747_fix_active_index/down.sql +++ b/migrations/2023-02-01-012747_fix_active_index/down.sql @@ -1,6 +1,6 @@ -drop index - idx_post_aggregates_featured_local_active, - idx_post_aggregates_featured_community_active; +DROP INDEX idx_post_aggregates_featured_local_active, idx_post_aggregates_featured_community_active; + +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank (score, newest_comment_time) DESC, newest_comment_time DESC); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank(score, newest_comment_time) desc, newest_comment_time desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank(score, newest_comment_time) desc, newest_comment_time desc); diff --git a/migrations/2023-02-01-012747_fix_active_index/up.sql b/migrations/2023-02-01-012747_fix_active_index/up.sql index 5673cf452..2219ebc76 100644 --- a/migrations/2023-02-01-012747_fix_active_index/up.sql +++ b/migrations/2023-02-01-012747_fix_active_index/up.sql @@ -1,7 +1,7 @@ -- This should use the newest_comment_time_necro, not the newest_comment_time for the hot_rank -drop index - idx_post_aggregates_featured_local_active, - idx_post_aggregates_featured_community_active; +DROP INDEX idx_post_aggregates_featured_local_active, idx_post_aggregates_featured_community_active; + +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank (score, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank (score, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank(score, newest_comment_time_necro) desc, newest_comment_time_necro desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank(score, newest_comment_time_necro) desc, newest_comment_time_necro desc); diff --git a/migrations/2023-02-05-102549_drop-site-federation-debug/down.sql b/migrations/2023-02-05-102549_drop-site-federation-debug/down.sql index 1ac320f2f..4e141e423 100644 --- a/migrations/2023-02-05-102549_drop-site-federation-debug/down.sql +++ b/migrations/2023-02-05-102549_drop-site-federation-debug/down.sql @@ -1 +1,3 @@ -alter table local_site add column federation_debug int default 0; \ No newline at end of file +ALTER TABLE local_site + ADD COLUMN federation_debug int DEFAULT 0; + diff --git a/migrations/2023-02-05-102549_drop-site-federation-debug/up.sql b/migrations/2023-02-05-102549_drop-site-federation-debug/up.sql index c7286d09c..cad1c8975 100644 --- a/migrations/2023-02-05-102549_drop-site-federation-debug/up.sql +++ b/migrations/2023-02-05-102549_drop-site-federation-debug/up.sql @@ -1 +1,3 @@ -alter table local_site drop column federation_debug; \ No newline at end of file +ALTER TABLE local_site + DROP COLUMN federation_debug; + diff --git a/migrations/2023-02-07-030958_community-collections/down.sql b/migrations/2023-02-07-030958_community-collections/down.sql index 8f7b531f0..e3aa8bad9 100644 --- a/migrations/2023-02-07-030958_community-collections/down.sql +++ b/migrations/2023-02-07-030958_community-collections/down.sql @@ -1,2 +1,6 @@ -alter table community drop column moderators_url; -alter table community drop column featured_url; \ No newline at end of file +ALTER TABLE community + DROP COLUMN moderators_url; + +ALTER TABLE community + DROP COLUMN featured_url; + diff --git a/migrations/2023-02-07-030958_community-collections/up.sql b/migrations/2023-02-07-030958_community-collections/up.sql index 78e7e52b8..f8be41a96 100644 --- a/migrations/2023-02-07-030958_community-collections/up.sql +++ b/migrations/2023-02-07-030958_community-collections/up.sql @@ -1,2 +1,6 @@ -alter table community add column moderators_url varchar(255) unique; -alter table community add column featured_url varchar(255) unique; \ No newline at end of file +ALTER TABLE community + ADD COLUMN moderators_url varchar(255) UNIQUE; + +ALTER TABLE community + ADD COLUMN featured_url varchar(255) UNIQUE; + diff --git a/migrations/2023-02-11-173347_custom_emojis/down.sql b/migrations/2023-02-11-173347_custom_emojis/down.sql index 8994bb3be..01a68d2d2 100644 --- a/migrations/2023-02-11-173347_custom_emojis/down.sql +++ b/migrations/2023-02-11-173347_custom_emojis/down.sql @@ -1,2 +1,4 @@ -drop table custom_emoji_keyword; -drop table custom_emoji; \ No newline at end of file +DROP TABLE custom_emoji_keyword; + +DROP TABLE custom_emoji; + diff --git a/migrations/2023-02-11-173347_custom_emojis/up.sql b/migrations/2023-02-11-173347_custom_emojis/up.sql index 79a21b206..98b6fa59c 100644 --- a/migrations/2023-02-11-173347_custom_emojis/up.sql +++ b/migrations/2023-02-11-173347_custom_emojis/up.sql @@ -1,19 +1,20 @@ -create table custom_emoji ( - id serial primary key, - local_site_id int references local_site on update cascade on delete cascade not null, - shortcode varchar(128) not null UNIQUE, - image_url text not null UNIQUE, - alt_text text not null, - category text not null, - published timestamp without time zone default now() not null, - updated timestamp without time zone +CREATE TABLE custom_emoji ( + id serial PRIMARY KEY, + local_site_id int REFERENCES local_site ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + shortcode varchar(128) NOT NULL UNIQUE, + image_url text NOT NULL UNIQUE, + alt_text text NOT NULL, + category text NOT NULL, + published timestamp without time zone DEFAULT now() NOT NULL, + updated timestamp without time zone ); -create table custom_emoji_keyword ( - id serial primary key, - custom_emoji_id int references custom_emoji on update cascade on delete cascade not null, - keyword varchar(128) not null, - UNIQUE (custom_emoji_id, keyword) +CREATE TABLE custom_emoji_keyword ( + id serial PRIMARY KEY, + custom_emoji_id int REFERENCES custom_emoji ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, + keyword varchar(128) NOT NULL, + UNIQUE (custom_emoji_id, keyword) ); -create index idx_custom_emoji_category on custom_emoji (id,category); +CREATE INDEX idx_custom_emoji_category ON custom_emoji (id, category); + diff --git a/migrations/2023-02-13-172528_add_report_email_admins/down.sql b/migrations/2023-02-13-172528_add_report_email_admins/down.sql index fa69bbaf4..148f35d93 100644 --- a/migrations/2023-02-13-172528_add_report_email_admins/down.sql +++ b/migrations/2023-02-13-172528_add_report_email_admins/down.sql @@ -1 +1,3 @@ -alter table local_site drop column reports_email_admins; +ALTER TABLE local_site + DROP COLUMN reports_email_admins; + diff --git a/migrations/2023-02-13-172528_add_report_email_admins/up.sql b/migrations/2023-02-13-172528_add_report_email_admins/up.sql index 7de8a2842..069df1453 100644 --- a/migrations/2023-02-13-172528_add_report_email_admins/up.sql +++ b/migrations/2023-02-13-172528_add_report_email_admins/up.sql @@ -1,2 +1,4 @@ -- Adding a field to email admins for new reports -alter table local_site add column reports_email_admins boolean not null default false; +ALTER TABLE local_site + ADD COLUMN reports_email_admins boolean NOT NULL DEFAULT FALSE; + diff --git a/migrations/2023-02-13-221303_add_instance_software_and_version/down.sql b/migrations/2023-02-13-221303_add_instance_software_and_version/down.sql index 07179de1d..fbac63e18 100644 --- a/migrations/2023-02-13-221303_add_instance_software_and_version/down.sql +++ b/migrations/2023-02-13-221303_add_instance_software_and_version/down.sql @@ -1,2 +1,6 @@ -alter table instance drop column software; -alter table instance drop column version; +ALTER TABLE instance + DROP COLUMN software; + +ALTER TABLE instance + DROP COLUMN version; + diff --git a/migrations/2023-02-13-221303_add_instance_software_and_version/up.sql b/migrations/2023-02-13-221303_add_instance_software_and_version/up.sql index abfeb8500..a7f7233cb 100644 --- a/migrations/2023-02-13-221303_add_instance_software_and_version/up.sql +++ b/migrations/2023-02-13-221303_add_instance_software_and_version/up.sql @@ -1,4 +1,7 @@ -- Add Software and Version columns from nodeinfo to the instance table +ALTER TABLE instance + ADD COLUMN software varchar(255); + +ALTER TABLE instance + ADD COLUMN version varchar(255); -alter table instance add column software varchar(255); -alter table instance add column version varchar(255); diff --git a/migrations/2023-02-15-212546_add_post_comment_saved_indexes/down.sql b/migrations/2023-02-15-212546_add_post_comment_saved_indexes/down.sql index 3ef1500c6..bd9b6bba6 100644 --- a/migrations/2023-02-15-212546_add_post_comment_saved_indexes/down.sql +++ b/migrations/2023-02-15-212546_add_post_comment_saved_indexes/down.sql @@ -1 +1,2 @@ -drop index idx_post_saved_person_id, idx_comment_saved_person_id; +DROP INDEX idx_post_saved_person_id, idx_comment_saved_person_id; + diff --git a/migrations/2023-02-15-212546_add_post_comment_saved_indexes/up.sql b/migrations/2023-02-15-212546_add_post_comment_saved_indexes/up.sql index 889943121..98db27798 100644 --- a/migrations/2023-02-15-212546_add_post_comment_saved_indexes/up.sql +++ b/migrations/2023-02-15-212546_add_post_comment_saved_indexes/up.sql @@ -1,2 +1,4 @@ -create index idx_post_saved_person_id on post_saved (person_id); -create index idx_comment_saved_person_id on comment_saved (person_id); +CREATE INDEX idx_post_saved_person_id ON post_saved (person_id); + +CREATE INDEX idx_comment_saved_person_id ON comment_saved (person_id); + diff --git a/migrations/2023-02-16-194139_add_totp_secret/down.sql b/migrations/2023-02-16-194139_add_totp_secret/down.sql index b7f38c457..7adf97e66 100644 --- a/migrations/2023-02-16-194139_add_totp_secret/down.sql +++ b/migrations/2023-02-16-194139_add_totp_secret/down.sql @@ -1,2 +1,6 @@ -alter table local_user drop column totp_2fa_secret; -alter table local_user drop column totp_2fa_url; +ALTER TABLE local_user + DROP COLUMN totp_2fa_secret; + +ALTER TABLE local_user + DROP COLUMN totp_2fa_url; + diff --git a/migrations/2023-02-16-194139_add_totp_secret/up.sql b/migrations/2023-02-16-194139_add_totp_secret/up.sql index e40c1c66f..43ff8dc90 100644 --- a/migrations/2023-02-16-194139_add_totp_secret/up.sql +++ b/migrations/2023-02-16-194139_add_totp_secret/up.sql @@ -1,2 +1,6 @@ -alter table local_user add column totp_2fa_secret text; -alter table local_user add column totp_2fa_url text; +ALTER TABLE local_user + ADD COLUMN totp_2fa_secret text; + +ALTER TABLE local_user + ADD COLUMN totp_2fa_url text; + diff --git a/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/down.sql b/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/down.sql index 5d5f2f3a5..ceb36f538 100644 --- a/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/down.sql +++ b/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/down.sql @@ -1,62 +1,126 @@ -- Some fixes -alter table community alter column hidden drop not null; -alter table community alter column posting_restricted_to_mods drop not null; -alter table activity alter column sensitive drop not null; -alter table mod_add alter column removed drop not null; -alter table mod_add_community alter column removed drop not null; -alter table mod_ban alter column banned drop not null; -alter table mod_ban_from_community alter column banned drop not null; -alter table mod_hide_community alter column hidden drop not null; -alter table mod_lock_post alter column locked drop not null; -alter table mod_remove_comment alter column removed drop not null; -alter table mod_remove_community alter column removed drop not null; -alter table mod_remove_post alter column removed drop not null; -alter table mod_transfer_community add column removed boolean default false; -alter table language alter column code drop not null; -alter table language alter column name drop not null; +ALTER TABLE community + ALTER COLUMN hidden DROP NOT NULL; + +ALTER TABLE community + ALTER COLUMN posting_restricted_to_mods DROP NOT NULL; + +ALTER TABLE activity + ALTER COLUMN sensitive DROP NOT NULL; + +ALTER TABLE mod_add + ALTER COLUMN removed DROP NOT NULL; + +ALTER TABLE mod_add_community + ALTER COLUMN removed DROP NOT NULL; + +ALTER TABLE mod_ban + ALTER COLUMN banned DROP NOT NULL; + +ALTER TABLE mod_ban_from_community + ALTER COLUMN banned DROP NOT NULL; + +ALTER TABLE mod_hide_community + ALTER COLUMN hidden DROP NOT NULL; + +ALTER TABLE mod_lock_post + ALTER COLUMN LOCKED DROP NOT NULL; + +ALTER TABLE mod_remove_comment + ALTER COLUMN removed DROP NOT NULL; + +ALTER TABLE mod_remove_community + ALTER COLUMN removed DROP NOT NULL; + +ALTER TABLE mod_remove_post + ALTER COLUMN removed DROP NOT NULL; + +ALTER TABLE mod_transfer_community + ADD COLUMN removed boolean DEFAULT FALSE; + +ALTER TABLE LANGUAGE + ALTER COLUMN code DROP NOT NULL; + +ALTER TABLE LANGUAGE + ALTER COLUMN name DROP NOT NULL; -- Fix the registration mode enums ALTER TYPE registration_mode_enum RENAME VALUE 'Closed' TO 'closed'; + ALTER TYPE registration_mode_enum RENAME VALUE 'RequireApplication' TO 'require_application'; + ALTER TYPE registration_mode_enum RENAME VALUE 'Open' TO 'open'; -- add back old columns - -- Alter the local_user table -alter table local_user alter column default_sort_type drop default; -alter table local_user alter column default_sort_type type smallint using - case default_sort_type - when 'Active' then 0 - when 'Hot' then 1 - when 'New' then 2 - when 'Old' then 3 - when 'TopDay' then 4 - when 'TopWeek' then 5 - when 'TopMonth' then 6 - when 'TopYear' then 7 - when 'TopAll' then 8 - when 'MostComments' then 9 - when 'NewComments' then 10 - else 0 - end; -alter table local_user alter column default_sort_type set default 0; +ALTER TABLE local_user + ALTER COLUMN default_sort_type DROP DEFAULT; -alter table local_user alter column default_listing_type drop default; -alter table local_user alter column default_listing_type type smallint using - case default_listing_type - when 'All' then 0 - when 'Local' then 1 - when 'Subscribed' then 2 - else 1 - end; -alter table local_user alter column default_listing_type set default 1; +ALTER TABLE local_user + ALTER COLUMN default_sort_type TYPE smallint + USING + CASE default_sort_type + WHEN 'Active' THEN + 0 + WHEN 'Hot' THEN + 1 + WHEN 'New' THEN + 2 + WHEN 'Old' THEN + 3 + WHEN 'TopDay' THEN + 4 + WHEN 'TopWeek' THEN + 5 + WHEN 'TopMonth' THEN + 6 + WHEN 'TopYear' THEN + 7 + WHEN 'TopAll' THEN + 8 + WHEN 'MostComments' THEN + 9 + WHEN 'NewComments' THEN + 10 + ELSE + 0 + END; + +ALTER TABLE local_user + ALTER COLUMN default_sort_type SET DEFAULT 0; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type DROP DEFAULT; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type TYPE smallint + USING + CASE default_listing_type + WHEN 'All' THEN + 0 + WHEN 'Local' THEN + 1 + WHEN 'Subscribed' THEN + 2 + ELSE + 1 + END; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type SET DEFAULT 1; -- Alter the local site column +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type DROP DEFAULT; -alter table local_site alter column default_post_listing_type drop default; -alter table local_site alter column default_post_listing_type type text; -alter table local_site alter column default_post_listing_type set default 1; +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type TYPE text; + +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type SET DEFAULT 1; -- Drop the types -drop type listing_type_enum; -drop type sort_type_enum; +DROP TYPE listing_type_enum; + +DROP TYPE sort_type_enum; + diff --git a/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/up.sql b/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/up.sql index 8474f34ed..bfce9a6a1 100644 --- a/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/up.sql +++ b/migrations/2023-04-14-175955_add_listingtype_sorttype_enums/up.sql @@ -1,61 +1,142 @@ -- A few DB fixes -alter table community alter column hidden set not null; -alter table community alter column posting_restricted_to_mods set not null; -alter table activity alter column sensitive set not null; -alter table mod_add alter column removed set not null; -alter table mod_add_community alter column removed set not null; -alter table mod_ban alter column banned set not null; -alter table mod_ban_from_community alter column banned set not null; -alter table mod_hide_community alter column hidden set not null; -alter table mod_lock_post alter column locked set not null; -alter table mod_remove_comment alter column removed set not null; -alter table mod_remove_community alter column removed set not null; -alter table mod_remove_post alter column removed set not null; -alter table mod_transfer_community drop column removed; -alter table language alter column code set not null; -alter table language alter column name set not null; +ALTER TABLE community + ALTER COLUMN hidden SET NOT NULL; + +ALTER TABLE community + ALTER COLUMN posting_restricted_to_mods SET NOT NULL; + +ALTER TABLE activity + ALTER COLUMN sensitive SET NOT NULL; + +ALTER TABLE mod_add + ALTER COLUMN removed SET NOT NULL; + +ALTER TABLE mod_add_community + ALTER COLUMN removed SET NOT NULL; + +ALTER TABLE mod_ban + ALTER COLUMN banned SET NOT NULL; + +ALTER TABLE mod_ban_from_community + ALTER COLUMN banned SET NOT NULL; + +ALTER TABLE mod_hide_community + ALTER COLUMN hidden SET NOT NULL; + +ALTER TABLE mod_lock_post + ALTER COLUMN LOCKED SET NOT NULL; + +ALTER TABLE mod_remove_comment + ALTER COLUMN removed SET NOT NULL; + +ALTER TABLE mod_remove_community + ALTER COLUMN removed SET NOT NULL; + +ALTER TABLE mod_remove_post + ALTER COLUMN removed SET NOT NULL; + +ALTER TABLE mod_transfer_community + DROP COLUMN removed; + +ALTER TABLE LANGUAGE + ALTER COLUMN code SET NOT NULL; + +ALTER TABLE LANGUAGE + ALTER COLUMN name SET NOT NULL; -- Fix the registration mode enums ALTER TYPE registration_mode_enum RENAME VALUE 'closed' TO 'Closed'; + ALTER TYPE registration_mode_enum RENAME VALUE 'require_application' TO 'RequireApplication'; + ALTER TYPE registration_mode_enum RENAME VALUE 'open' TO 'Open'; -- Create the enums +CREATE TYPE sort_type_enum AS ENUM ( + 'Active', + 'Hot', + 'New', + 'Old', + 'TopDay', + 'TopWeek', + 'TopMonth', + 'TopYear', + 'TopAll', + 'MostComments', + 'NewComments' +); -CREATE TYPE sort_type_enum AS ENUM ('Active', 'Hot', 'New', 'Old', 'TopDay', 'TopWeek', 'TopMonth', 'TopYear', 'TopAll', 'MostComments', 'NewComments'); - -CREATE TYPE listing_type_enum AS ENUM ('All', 'Local', 'Subscribed'); +CREATE TYPE listing_type_enum AS ENUM ( + 'All', + 'Local', + 'Subscribed' +); -- Alter the local_user table -alter table local_user alter column default_sort_type drop default; -alter table local_user alter column default_sort_type type sort_type_enum using - case default_sort_type - when 0 then 'Active' - when 1 then 'Hot' - when 2 then 'New' - when 3 then 'Old' - when 4 then 'TopDay' - when 5 then 'TopWeek' - when 6 then 'TopMonth' - when 7 then 'TopYear' - when 8 then 'TopAll' - when 9 then 'MostComments' - when 10 then 'NewComments' - else 'Active' - end :: sort_type_enum; -alter table local_user alter column default_sort_type set default 'Active'; +ALTER TABLE local_user + ALTER COLUMN default_sort_type DROP DEFAULT; -alter table local_user alter column default_listing_type drop default; -alter table local_user alter column default_listing_type type listing_type_enum using - case default_listing_type - when 0 then 'All' - when 1 then 'Local' - when 2 then 'Subscribed' - else 'Local' - end :: listing_type_enum; -alter table local_user alter column default_listing_type set default 'Local'; +ALTER TABLE local_user + ALTER COLUMN default_sort_type TYPE sort_type_enum + USING + CASE default_sort_type + WHEN 0 THEN + 'Active' + WHEN 1 THEN + 'Hot' + WHEN 2 THEN + 'New' + WHEN 3 THEN + 'Old' + WHEN 4 THEN + 'TopDay' + WHEN 5 THEN + 'TopWeek' + WHEN 6 THEN + 'TopMonth' + WHEN 7 THEN + 'TopYear' + WHEN 8 THEN + 'TopAll' + WHEN 9 THEN + 'MostComments' + WHEN 10 THEN + 'NewComments' + ELSE + 'Active' + END::sort_type_enum; + +ALTER TABLE local_user + ALTER COLUMN default_sort_type SET DEFAULT 'Active'; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type DROP DEFAULT; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type TYPE listing_type_enum + USING + CASE default_listing_type + WHEN 0 THEN + 'All' + WHEN 1 THEN + 'Local' + WHEN 2 THEN + 'Subscribed' + ELSE + 'Local' + END::listing_type_enum; + +ALTER TABLE local_user + ALTER COLUMN default_listing_type SET DEFAULT 'Local'; -- Alter the local site column -alter table local_site alter column default_post_listing_type drop default; -alter table local_site alter column default_post_listing_type type listing_type_enum using default_post_listing_type::listing_type_enum; -alter table local_site alter column default_post_listing_type set default 'Local'; +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type DROP DEFAULT; + +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type TYPE listing_type_enum + USING default_post_listing_type::listing_type_enum; + +ALTER TABLE local_site + ALTER COLUMN default_post_listing_type SET DEFAULT 'Local'; + diff --git a/migrations/2023-04-23-164732_add_person_details_indexes/down.sql b/migrations/2023-04-23-164732_add_person_details_indexes/down.sql index 67879de43..d32b21ecb 100644 --- a/migrations/2023-04-23-164732_add_person_details_indexes/down.sql +++ b/migrations/2023-04-23-164732_add_person_details_indexes/down.sql @@ -1,21 +1,42 @@ -drop index idx_person_lower_name; -drop index idx_community_lower_name; -drop index idx_community_moderator_published; -drop index idx_community_moderator_community; -drop index idx_community_moderator_person; -drop index idx_comment_saved_comment; -drop index idx_comment_saved_person; -drop index idx_community_block_community; -drop index idx_community_block_person; -drop index idx_community_follower_community; -drop index idx_community_follower_person; -drop index idx_person_block_person; -drop index idx_person_block_target; -drop index idx_post_language; -drop index idx_comment_language; -drop index idx_person_aggregates_person; -drop index idx_person_post_aggregates_post; -drop index idx_person_post_aggregates_person; -drop index idx_comment_reply_comment; -drop index idx_comment_reply_recipient; -drop index idx_comment_reply_published; \ No newline at end of file +DROP INDEX idx_person_lower_name; + +DROP INDEX idx_community_lower_name; + +DROP INDEX idx_community_moderator_published; + +DROP INDEX idx_community_moderator_community; + +DROP INDEX idx_community_moderator_person; + +DROP INDEX idx_comment_saved_comment; + +DROP INDEX idx_comment_saved_person; + +DROP INDEX idx_community_block_community; + +DROP INDEX idx_community_block_person; + +DROP INDEX idx_community_follower_community; + +DROP INDEX idx_community_follower_person; + +DROP INDEX idx_person_block_person; + +DROP INDEX idx_person_block_target; + +DROP INDEX idx_post_language; + +DROP INDEX idx_comment_language; + +DROP INDEX idx_person_aggregates_person; + +DROP INDEX idx_person_post_aggregates_post; + +DROP INDEX idx_person_post_aggregates_person; + +DROP INDEX idx_comment_reply_comment; + +DROP INDEX idx_comment_reply_recipient; + +DROP INDEX idx_comment_reply_published; + diff --git a/migrations/2023-04-23-164732_add_person_details_indexes/up.sql b/migrations/2023-04-23-164732_add_person_details_indexes/up.sql index df3dde7e3..c6a340f17 100644 --- a/migrations/2023-04-23-164732_add_person_details_indexes/up.sql +++ b/migrations/2023-04-23-164732_add_person_details_indexes/up.sql @@ -1,31 +1,43 @@ -- Add a few indexes to speed up person details queries -create index idx_person_lower_name on person (lower(name)); -create index idx_community_lower_name on community (lower(name)); +CREATE INDEX idx_person_lower_name ON person (lower(name)); -create index idx_community_moderator_published on community_moderator (published); -create index idx_community_moderator_community on community_moderator (community_id); -create index idx_community_moderator_person on community_moderator (person_id); +CREATE INDEX idx_community_lower_name ON community (lower(name)); -create index idx_comment_saved_comment on comment_saved (comment_id); -create index idx_comment_saved_person on comment_saved (person_id); +CREATE INDEX idx_community_moderator_published ON community_moderator (published); -create index idx_community_block_community on community_block (community_id); -create index idx_community_block_person on community_block (person_id); +CREATE INDEX idx_community_moderator_community ON community_moderator (community_id); -create index idx_community_follower_community on community_follower (community_id); -create index idx_community_follower_person on community_follower (person_id); +CREATE INDEX idx_community_moderator_person ON community_moderator (person_id); -create index idx_person_block_person on person_block (person_id); -create index idx_person_block_target on person_block (target_id); +CREATE INDEX idx_comment_saved_comment ON comment_saved (comment_id); -create index idx_post_language on post (language_id); -create index idx_comment_language on comment (language_id); +CREATE INDEX idx_comment_saved_person ON comment_saved (person_id); -create index idx_person_aggregates_person on person_aggregates (person_id); +CREATE INDEX idx_community_block_community ON community_block (community_id); -create index idx_person_post_aggregates_post on person_post_aggregates (post_id); -create index idx_person_post_aggregates_person on person_post_aggregates (person_id); +CREATE INDEX idx_community_block_person ON community_block (person_id); + +CREATE INDEX idx_community_follower_community ON community_follower (community_id); + +CREATE INDEX idx_community_follower_person ON community_follower (person_id); + +CREATE INDEX idx_person_block_person ON person_block (person_id); + +CREATE INDEX idx_person_block_target ON person_block (target_id); + +CREATE INDEX idx_post_language ON post (language_id); + +CREATE INDEX idx_comment_language ON comment (language_id); + +CREATE INDEX idx_person_aggregates_person ON person_aggregates (person_id); + +CREATE INDEX idx_person_post_aggregates_post ON person_post_aggregates (post_id); + +CREATE INDEX idx_person_post_aggregates_person ON person_post_aggregates (person_id); + +CREATE INDEX idx_comment_reply_comment ON comment_reply (comment_id); + +CREATE INDEX idx_comment_reply_recipient ON comment_reply (recipient_id); + +CREATE INDEX idx_comment_reply_published ON comment_reply (published DESC); -create index idx_comment_reply_comment on comment_reply (comment_id); -create index idx_comment_reply_recipient on comment_reply (recipient_id); -create index idx_comment_reply_published on comment_reply (published desc); diff --git a/migrations/2023-05-10-095739_force_enable_undetermined_language/up.sql b/migrations/2023-05-10-095739_force_enable_undetermined_language/up.sql index b320ecad4..8b501d5b0 100644 --- a/migrations/2023-05-10-095739_force_enable_undetermined_language/up.sql +++ b/migrations/2023-05-10-095739_force_enable_undetermined_language/up.sql @@ -1,4 +1,11 @@ -- force enable undetermined language for all users -insert into local_user_language (local_user_id, language_id) - select id, 0 from local_user - on conflict (local_user_id, language_id) do nothing; +INSERT INTO local_user_language (local_user_id, language_id) +SELECT + id, + 0 +FROM + local_user +ON CONFLICT (local_user_id, + language_id) + DO NOTHING; + diff --git a/migrations/2023-06-06-104440_index_post_url/down.sql b/migrations/2023-06-06-104440_index_post_url/down.sql index ccc9e938f..7ddea79cc 100644 --- a/migrations/2023-06-06-104440_index_post_url/down.sql +++ b/migrations/2023-06-06-104440_index_post_url/down.sql @@ -1,5 +1,7 @@ -- Change back the column type -alter table post alter column url type text; +ALTER TABLE post + ALTER COLUMN url TYPE text; -- Drop the index -drop index idx_post_url; +DROP INDEX idx_post_url; + diff --git a/migrations/2023-06-06-104440_index_post_url/up.sql b/migrations/2023-06-06-104440_index_post_url/up.sql index ce3532887..5e0f11463 100644 --- a/migrations/2023-06-06-104440_index_post_url/up.sql +++ b/migrations/2023-06-06-104440_index_post_url/up.sql @@ -1,9 +1,18 @@ -- Make a hard limit of 512 for the post.url column -- Truncate existing long rows. -update post set url = left(url, 512) where length(url) > 512; +UPDATE + post +SET + url = + LEFT (url, + 512) +WHERE + length(url) > 512; -- Enforce the limit -alter table post alter column url type varchar (512); +ALTER TABLE post + ALTER COLUMN url TYPE varchar(512); -- Add the index -create index idx_post_url on post(url); +CREATE INDEX idx_post_url ON post (url); + diff --git a/migrations/2023-06-07-105918_add_hot_rank_columns/down.sql b/migrations/2023-06-07-105918_add_hot_rank_columns/down.sql index 71529bdf0..e82fdff38 100644 --- a/migrations/2023-06-07-105918_add_hot_rank_columns/down.sql +++ b/migrations/2023-06-07-105918_add_hot_rank_columns/down.sql @@ -1,35 +1,55 @@ - -- Remove the new columns +ALTER TABLE post_aggregates + DROP COLUMN hot_rank; -alter table post_aggregates drop column hot_rank; -alter table post_aggregates drop column hot_rank_active; +ALTER TABLE post_aggregates + DROP COLUMN hot_rank_active; -alter table comment_aggregates drop column hot_rank; +ALTER TABLE comment_aggregates + DROP COLUMN hot_rank; -alter table community_aggregates drop column hot_rank; +ALTER TABLE community_aggregates + DROP COLUMN hot_rank; -- Drop some new indexes -drop index idx_post_aggregates_score; -drop index idx_post_aggregates_published; -drop index idx_post_aggregates_newest_comment_time; -drop index idx_post_aggregates_newest_comment_time_necro; -drop index idx_post_aggregates_featured_community; -drop index idx_post_aggregates_featured_local; +DROP INDEX idx_post_aggregates_score; + +DROP INDEX idx_post_aggregates_published; + +DROP INDEX idx_post_aggregates_newest_comment_time; + +DROP INDEX idx_post_aggregates_newest_comment_time_necro; + +DROP INDEX idx_post_aggregates_featured_community; + +DROP INDEX idx_post_aggregates_featured_local; -- Recreate the old indexes CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time ON public.post_aggregates USING btree (featured_local DESC, newest_comment_time DESC); + CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time ON public.post_aggregates USING btree (featured_community DESC, newest_comment_time DESC); + CREATE INDEX idx_post_aggregates_featured_local_comments ON public.post_aggregates USING btree (featured_local DESC, comments DESC); + CREATE INDEX idx_post_aggregates_featured_community_comments ON public.post_aggregates USING btree (featured_community DESC, comments DESC); -CREATE INDEX idx_post_aggregates_featured_local_hot ON public.post_aggregates USING btree (featured_local DESC, hot_rank((score)::numeric, published) DESC, published DESC); -CREATE INDEX idx_post_aggregates_featured_community_hot ON public.post_aggregates USING btree (featured_community DESC, hot_rank((score)::numeric, published) DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_local_hot ON public.post_aggregates USING btree (featured_local DESC, hot_rank ((score)::numeric, published) DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_community_hot ON public.post_aggregates USING btree (featured_community DESC, hot_rank ((score)::numeric, published) DESC, published DESC); + CREATE INDEX idx_post_aggregates_featured_local_score ON public.post_aggregates USING btree (featured_local DESC, score DESC); + CREATE INDEX idx_post_aggregates_featured_community_score ON public.post_aggregates USING btree (featured_community DESC, score DESC); + CREATE INDEX idx_post_aggregates_featured_local_published ON public.post_aggregates USING btree (featured_local DESC, published DESC); + CREATE INDEX idx_post_aggregates_featured_community_published ON public.post_aggregates USING btree (featured_community DESC, published DESC); -CREATE INDEX idx_post_aggregates_featured_local_active ON public.post_aggregates USING btree (featured_local DESC, hot_rank((score)::numeric, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); -CREATE INDEX idx_post_aggregates_featured_community_active ON public.post_aggregates USING btree (featured_community DESC, hot_rank((score)::numeric, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); -CREATE INDEX idx_comment_aggregates_hot ON public.comment_aggregates USING btree (hot_rank((score)::numeric, published) DESC, published DESC); +CREATE INDEX idx_post_aggregates_featured_local_active ON public.post_aggregates USING btree (featured_local DESC, hot_rank ((score)::numeric, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON public.post_aggregates USING btree (featured_community DESC, hot_rank ((score)::numeric, newest_comment_time_necro) DESC, newest_comment_time_necro DESC); + +CREATE INDEX idx_comment_aggregates_hot ON public.comment_aggregates USING btree (hot_rank ((score)::numeric, published) DESC, published DESC); + +CREATE INDEX idx_community_aggregates_hot ON public.community_aggregates USING btree (hot_rank ((subscribers)::numeric, published) DESC, published DESC); -CREATE INDEX idx_community_aggregates_hot ON public.community_aggregates USING btree (hot_rank((subscribers)::numeric, published) DESC, published DESC); diff --git a/migrations/2023-06-07-105918_add_hot_rank_columns/up.sql b/migrations/2023-06-07-105918_add_hot_rank_columns/up.sql index 92f03e5f3..00c8fae2d 100644 --- a/migrations/2023-06-07-105918_add_hot_rank_columns/up.sql +++ b/migrations/2023-06-07-105918_add_hot_rank_columns/up.sql @@ -1,17 +1,27 @@ -- This converts the old hot_rank functions, to columns - -- Remove the old compound indexes DROP INDEX idx_post_aggregates_featured_local_newest_comment_time; + DROP INDEX idx_post_aggregates_featured_community_newest_comment_time; + DROP INDEX idx_post_aggregates_featured_local_comments; + DROP INDEX idx_post_aggregates_featured_community_comments; + DROP INDEX idx_post_aggregates_featured_local_hot; + DROP INDEX idx_post_aggregates_featured_community_hot; + DROP INDEX idx_post_aggregates_featured_local_score; + DROP INDEX idx_post_aggregates_featured_community_score; + DROP INDEX idx_post_aggregates_featured_local_published; + DROP INDEX idx_post_aggregates_featured_community_published; + DROP INDEX idx_post_aggregates_featured_local_active; + DROP INDEX idx_post_aggregates_featured_community_active; DROP INDEX idx_comment_aggregates_hot; @@ -21,31 +31,59 @@ DROP INDEX idx_community_aggregates_hot; -- Add the new hot rank columns for post and comment aggregates -- Note: 1728 is the result of the hot_rank function, with a score of 1, posted now -- hot_rank = 10000*log10(1 + 3)/Power(2, 1.8) -alter table post_aggregates add column hot_rank integer not null default 1728; -alter table post_aggregates add column hot_rank_active integer not null default 1728; +ALTER TABLE post_aggregates + ADD COLUMN hot_rank integer NOT NULL DEFAULT 1728; -alter table comment_aggregates add column hot_rank integer not null default 1728; +ALTER TABLE post_aggregates + ADD COLUMN hot_rank_active integer NOT NULL DEFAULT 1728; -alter table community_aggregates add column hot_rank integer not null default 1728; +ALTER TABLE comment_aggregates + ADD COLUMN hot_rank integer NOT NULL DEFAULT 1728; + +ALTER TABLE community_aggregates + ADD COLUMN hot_rank integer NOT NULL DEFAULT 1728; -- Populate them initially --- Note: After initial population, these are updated in a periodic scheduled job, +-- Note: After initial population, these are updated in a periodic scheduled job, -- with only the last week being updated. -update post_aggregates set hot_rank_active = hot_rank(score::numeric, newest_comment_time_necro); -update post_aggregates set hot_rank = hot_rank(score::numeric, published); -update comment_aggregates set hot_rank = hot_rank(score::numeric, published); -update community_aggregates set hot_rank = hot_rank(subscribers::numeric, published); +UPDATE + post_aggregates +SET + hot_rank_active = hot_rank (score::numeric, newest_comment_time_necro); + +UPDATE + post_aggregates +SET + hot_rank = hot_rank (score::numeric, published); + +UPDATE + comment_aggregates +SET + hot_rank = hot_rank (score::numeric, published); + +UPDATE + community_aggregates +SET + hot_rank = hot_rank (subscribers::numeric, published); -- Create single column indexes -create index idx_post_aggregates_score on post_aggregates (score desc); -create index idx_post_aggregates_published on post_aggregates (published desc); -create index idx_post_aggregates_newest_comment_time on post_aggregates (newest_comment_time desc); -create index idx_post_aggregates_newest_comment_time_necro on post_aggregates (newest_comment_time_necro desc); -create index idx_post_aggregates_featured_community on post_aggregates (featured_community desc); -create index idx_post_aggregates_featured_local on post_aggregates (featured_local desc); -create index idx_post_aggregates_hot on post_aggregates (hot_rank desc); -create index idx_post_aggregates_active on post_aggregates (hot_rank_active desc); +CREATE INDEX idx_post_aggregates_score ON post_aggregates (score DESC); -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank desc); +CREATE INDEX idx_post_aggregates_published ON post_aggregates (published DESC); + +CREATE INDEX idx_post_aggregates_newest_comment_time ON post_aggregates (newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_newest_comment_time_necro ON post_aggregates (newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_community ON post_aggregates (featured_community DESC); + +CREATE INDEX idx_post_aggregates_featured_local ON post_aggregates (featured_local DESC); + +CREATE INDEX idx_post_aggregates_hot ON post_aggregates (hot_rank DESC); + +CREATE INDEX idx_post_aggregates_active ON post_aggregates (hot_rank_active DESC); + +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank DESC); + +CREATE INDEX idx_community_aggregates_hot ON community_aggregates (hot_rank DESC); -create index idx_community_aggregates_hot on community_aggregates (hot_rank desc); diff --git a/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/down.sql b/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/down.sql index 006bb1083..bdf20b8eb 100644 --- a/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/down.sql +++ b/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/down.sql @@ -1,14 +1,34 @@ -- update the default sort type -update local_user set default_sort_type = 'TopDay' where default_sort_type in ('TopHour', 'TopSixHour', 'TopTwelveHour'); +UPDATE + local_user +SET + default_sort_type = 'TopDay' +WHERE + default_sort_type IN ('TopHour', 'TopSixHour', 'TopTwelveHour'); -- rename the old enum -alter type sort_type_enum rename to sort_type_enum__; +ALTER TYPE sort_type_enum RENAME TO sort_type_enum__; + -- create the new enum -CREATE TYPE sort_type_enum AS ENUM ('Active', 'Hot', 'New', 'Old', 'TopDay', 'TopWeek', 'TopMonth', 'TopYear', 'TopAll', 'MostComments', 'NewComments'); +CREATE TYPE sort_type_enum AS ENUM ( + 'Active', + 'Hot', + 'New', + 'Old', + 'TopDay', + 'TopWeek', + 'TopMonth', + 'TopYear', + 'TopAll', + 'MostComments', + 'NewComments' +); -- alter all you enum columns -alter table local_user - alter column default_sort_type type sort_type_enum using default_sort_type::text::sort_type_enum; +ALTER TABLE local_user + ALTER COLUMN default_sort_type TYPE sort_type_enum + USING default_sort_type::text::sort_type_enum; -- drop the old enum -drop type sort_type_enum__; \ No newline at end of file +DROP TYPE sort_type_enum__; + diff --git a/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/up.sql b/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/up.sql index 7e4b6fbd6..2068269e7 100644 --- a/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/up.sql +++ b/migrations/2023-06-17-175955_add_listingtype_sorttype_hour_enums/up.sql @@ -1,4 +1,10 @@ -- Update the enums -ALTER TYPE sort_type_enum ADD VALUE 'TopHour'; -ALTER TYPE sort_type_enum ADD VALUE 'TopSixHour'; -ALTER TYPE sort_type_enum ADD VALUE 'TopTwelveHour'; \ No newline at end of file +ALTER TYPE sort_type_enum + ADD VALUE 'TopHour'; + +ALTER TYPE sort_type_enum + ADD VALUE 'TopSixHour'; + +ALTER TYPE sort_type_enum + ADD VALUE 'TopTwelveHour'; + diff --git a/migrations/2023-06-19-055530_add_retry_worker_setting/down.sql b/migrations/2023-06-19-055530_add_retry_worker_setting/down.sql index e3c200a15..948d044fe 100644 --- a/migrations/2023-06-19-055530_add_retry_worker_setting/down.sql +++ b/migrations/2023-06-19-055530_add_retry_worker_setting/down.sql @@ -1 +1,3 @@ -alter table local_site add column federation_worker_count int default 64 not null; \ No newline at end of file +ALTER TABLE local_site + ADD COLUMN federation_worker_count int DEFAULT 64 NOT NULL; + diff --git a/migrations/2023-06-19-055530_add_retry_worker_setting/up.sql b/migrations/2023-06-19-055530_add_retry_worker_setting/up.sql index 2aac86f85..e4eb058ef 100644 --- a/migrations/2023-06-19-055530_add_retry_worker_setting/up.sql +++ b/migrations/2023-06-19-055530_add_retry_worker_setting/up.sql @@ -1 +1,3 @@ -alter table local_site drop column federation_worker_count; \ No newline at end of file +ALTER TABLE local_site + DROP COLUMN federation_worker_count; + diff --git a/migrations/2023-06-19-120700_no_double_deletion/down.sql b/migrations/2023-06-19-120700_no_double_deletion/down.sql index 947278023..aec7c653a 100644 --- a/migrations/2023-06-19-120700_no_double_deletion/down.sql +++ b/migrations/2023-06-19-120700_no_double_deletion/down.sql @@ -1,19 +1,20 @@ -- This file should undo anything in `up.sql` -create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) -RETURNS boolean -LANGUAGE plpgsql -as $$ - begin - IF (TG_OP = 'INSERT') THEN - return false; - end if; +CREATE OR REPLACE FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record) + RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + RETURN FALSE; + END IF; + IF (TG_OP = 'DELETE') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 'f' + AND NEW.deleted = 't') + OR (OLD.removed = 'f' + AND NEW.removed = 't')); +END +$$; - IF (TG_OP = 'DELETE') THEN - return true; - end if; - - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 'f' AND NEW.deleted = 't') OR - (OLD.removed = 'f' AND NEW.removed = 't') - ); -END $$; diff --git a/migrations/2023-06-19-120700_no_double_deletion/up.sql b/migrations/2023-06-19-120700_no_double_deletion/up.sql index bd6d1e58f..38ab5c7b5 100644 --- a/migrations/2023-06-19-120700_no_double_deletion/up.sql +++ b/migrations/2023-06-19-120700_no_double_deletion/up.sql @@ -1,67 +1,100 @@ -- Deleting after removing should not decrement the count twice. -create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) -RETURNS boolean -LANGUAGE plpgsql -as $$ - begin - IF (TG_OP = 'INSERT') THEN - return false; - end if; - - IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN - return true; - end if; - - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 'f' AND NEW.deleted = 't') OR - (OLD.removed = 'f' AND NEW.removed = 't') - ); -END $$; +CREATE OR REPLACE FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record) + RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + RETURN FALSE; + END IF; + IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 'f' + AND NEW.deleted = 't') + OR (OLD.removed = 'f' + AND NEW.removed = 't')); +END +$$; -- Recalculate proper comment count. -UPDATE person_aggregates - SET comment_count = cnt.count - FROM ( - SELECT creator_id, count(*) AS count FROM comment - WHERE deleted='f' AND removed='f' - GROUP BY creator_id - ) cnt - WHERE person_aggregates.person_id = cnt.creator_id; +UPDATE + person_aggregates +SET + comment_count = cnt.count +FROM ( + SELECT + creator_id, + count(*) AS count + FROM + comment + WHERE + deleted = 'f' + AND removed = 'f' + GROUP BY + creator_id) cnt +WHERE + person_aggregates.person_id = cnt.creator_id; -- Recalculate proper comment score. -UPDATE person_aggregates ua - SET comment_score = cd.score - FROM ( - SELECT u.id AS creator_id, - coalesce(0, sum(cl.score)) as score +UPDATE + person_aggregates ua +SET + comment_score = cd.score +FROM ( + SELECT + u.id AS creator_id, + coalesce(0, sum(cl.score)) AS score -- User join because comments could be empty - FROM person u - LEFT JOIN comment c ON u.id = c.creator_id AND c.deleted = 'f' AND c.removed = 'f' - LEFT JOIN comment_like cl ON c.id = cl.comment_id - GROUP BY u.id - ) cd - WHERE ua.person_id = cd.creator_id; + FROM + person u + LEFT JOIN comment c ON u.id = c.creator_id + AND c.deleted = 'f' + AND c.removed = 'f' + LEFT JOIN comment_like cl ON c.id = cl.comment_id +GROUP BY + u.id) cd +WHERE + ua.person_id = cd.creator_id; -- Recalculate proper post count. -UPDATE person_aggregates - SET post_count = cnt.count - FROM ( - SELECT creator_id, count(*) AS count FROM post - WHERE deleted='f' AND removed='f' - GROUP BY creator_id - ) cnt - WHERE person_aggregates.person_id = cnt.creator_id; +UPDATE + person_aggregates +SET + post_count = cnt.count +FROM ( + SELECT + creator_id, + count(*) AS count + FROM + post + WHERE + deleted = 'f' + AND removed = 'f' + GROUP BY + creator_id) cnt +WHERE + person_aggregates.person_id = cnt.creator_id; -- Recalculate proper post score. - UPDATE person_aggregates ua - SET post_score = pd.score - FROM ( - SELECT u.id AS creator_id, - coalesce(0, sum(pl.score)) AS score - -- User join because posts could be empty - FROM person u - LEFT JOIN post p ON u.id = p.creator_id AND p.deleted = 'f' AND p.removed = 'f' - LEFT JOIN post_like pl ON p.id = pl.post_id - GROUP BY u.id - ) pd - WHERE ua.person_id = pd.creator_id; +UPDATE + person_aggregates ua +SET + post_score = pd.score +FROM ( + SELECT + u.id AS creator_id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + person u + LEFT JOIN post p ON u.id = p.creator_id + AND p.deleted = 'f' + AND p.removed = 'f' + LEFT JOIN post_like pl ON p.id = pl.post_id +GROUP BY + u.id) pd +WHERE + ua.person_id = pd.creator_id; + diff --git a/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/down.sql b/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/down.sql index 5b135223e..694b62eee 100644 --- a/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/down.sql +++ b/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/down.sql @@ -1,14 +1,37 @@ -- update the default sort type -update local_user set default_sort_type = 'TopDay' where default_sort_type in ('TopThreeMonths', 'TopSixMonths', 'TopNineMonths'); +UPDATE + local_user +SET + default_sort_type = 'TopDay' +WHERE + default_sort_type IN ('TopThreeMonths', 'TopSixMonths', 'TopNineMonths'); -- rename the old enum -alter type sort_type_enum rename to sort_type_enum__; +ALTER TYPE sort_type_enum RENAME TO sort_type_enum__; + -- create the new enum -CREATE TYPE sort_type_enum AS ENUM ('Active', 'Hot', 'New', 'Old', 'TopDay', 'TopWeek', 'TopMonth', 'TopYear', 'TopAll', 'MostComments', 'NewComments', 'TopHour', 'TopSixHour', 'TopTwelveHour'); +CREATE TYPE sort_type_enum AS ENUM ( + 'Active', + 'Hot', + 'New', + 'Old', + 'TopDay', + 'TopWeek', + 'TopMonth', + 'TopYear', + 'TopAll', + 'MostComments', + 'NewComments', + 'TopHour', + 'TopSixHour', + 'TopTwelveHour' +); -- alter all you enum columns -alter table local_user - alter column default_sort_type type sort_type_enum using default_sort_type::text::sort_type_enum; +ALTER TABLE local_user + ALTER COLUMN default_sort_type TYPE sort_type_enum + USING default_sort_type::text::sort_type_enum; -- drop the old enum -drop type sort_type_enum__; +DROP TYPE sort_type_enum__; + diff --git a/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/up.sql b/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/up.sql index 85bcfad7c..7e5fcf77f 100644 --- a/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/up.sql +++ b/migrations/2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/up.sql @@ -1,4 +1,10 @@ -- Update the enums -ALTER TYPE sort_type_enum ADD VALUE 'TopThreeMonths'; -ALTER TYPE sort_type_enum ADD VALUE 'TopSixMonths'; -ALTER TYPE sort_type_enum ADD VALUE 'TopNineMonths'; +ALTER TYPE sort_type_enum + ADD VALUE 'TopThreeMonths'; + +ALTER TYPE sort_type_enum + ADD VALUE 'TopSixMonths'; + +ALTER TYPE sort_type_enum + ADD VALUE 'TopNineMonths'; + diff --git a/migrations/2023-06-21-153242_add_captcha/down.sql b/migrations/2023-06-21-153242_add_captcha/down.sql index 4e5b83042..ab0fc231e 100644 --- a/migrations/2023-06-21-153242_add_captcha/down.sql +++ b/migrations/2023-06-21-153242_add_captcha/down.sql @@ -1 +1,2 @@ -drop table captcha_answer; \ No newline at end of file +DROP TABLE captcha_answer; + diff --git a/migrations/2023-06-21-153242_add_captcha/up.sql b/migrations/2023-06-21-153242_add_captcha/up.sql index 5c566bc92..ede6f71fe 100644 --- a/migrations/2023-06-21-153242_add_captcha/up.sql +++ b/migrations/2023-06-21-153242_add_captcha/up.sql @@ -1,6 +1,7 @@ -create table captcha_answer ( - id serial primary key, - uuid uuid not null unique default gen_random_uuid(), - answer text not null, - published timestamp not null default now() +CREATE TABLE captcha_answer ( + id serial PRIMARY KEY, + uuid uuid NOT NULL UNIQUE DEFAULT gen_random_uuid (), + answer text NOT NULL, + published timestamp NOT NULL DEFAULT now() ); + diff --git a/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/down.sql b/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/down.sql index ae8c4c786..e7836108d 100644 --- a/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/down.sql +++ b/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/down.sql @@ -1,2 +1,4 @@ -- Add a no-op statement to prevent `diesel migration redo` errors -SELECT 1; +SELECT + 1; + diff --git a/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/up.sql b/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/up.sql index cbe3be9e5..605f0ca93 100644 --- a/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/up.sql +++ b/migrations/2023-06-22-051755_fix_local_communities_marked_non_local/up.sql @@ -1,5 +1,11 @@ -update community c -set local=true -from local_site ls - join site s on ls.site_id=s.id -where c.instance_id=s.instance_id and not c.local; +UPDATE + community c +SET + local = TRUE +FROM + local_site ls + JOIN site s ON ls.site_id = s.id +WHERE + c.instance_id = s.instance_id + AND NOT c.local; + diff --git a/migrations/2023-06-22-101245_increase_user_theme_column_size/down.sql b/migrations/2023-06-22-101245_increase_user_theme_column_size/down.sql index 0731e0682..64480d540 100644 --- a/migrations/2023-06-22-101245_increase_user_theme_column_size/down.sql +++ b/migrations/2023-06-22-101245_increase_user_theme_column_size/down.sql @@ -1,2 +1,6 @@ -alter table only local_user alter column theme TYPE character varying(20); -alter table only local_user alter column theme set default 'browser'::character varying; \ No newline at end of file +ALTER TABLE ONLY local_user + ALTER COLUMN theme TYPE character varying(20); + +ALTER TABLE ONLY local_user + ALTER COLUMN theme SET DEFAULT 'browser'::character varying; + diff --git a/migrations/2023-06-22-101245_increase_user_theme_column_size/up.sql b/migrations/2023-06-22-101245_increase_user_theme_column_size/up.sql index cbab25663..44f7dcf85 100644 --- a/migrations/2023-06-22-101245_increase_user_theme_column_size/up.sql +++ b/migrations/2023-06-22-101245_increase_user_theme_column_size/up.sql @@ -1,2 +1,6 @@ -alter table only local_user alter column theme type text; -alter table only local_user alter column theme set default 'browser'::text; +ALTER TABLE ONLY local_user + ALTER COLUMN theme TYPE text; + +ALTER TABLE ONLY local_user + ALTER COLUMN theme SET DEFAULT 'browser'::text; + diff --git a/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/down.sql b/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/down.sql index a4dfd50b2..72ac5f2f3 100644 --- a/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/down.sql +++ b/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/down.sql @@ -1 +1,3 @@ -alter table local_user drop column open_links_in_new_tab; +ALTER TABLE local_user + DROP COLUMN open_links_in_new_tab; + diff --git a/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/up.sql b/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/up.sql index 39a4b44a1..9bc198558 100644 --- a/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/up.sql +++ b/migrations/2023-06-24-072904_add_open_links_in_new_tab_setting/up.sql @@ -1 +1,3 @@ -alter table local_user add column open_links_in_new_tab boolean default false not null; +ALTER TABLE local_user + ADD COLUMN open_links_in_new_tab boolean DEFAULT FALSE NOT NULL; + diff --git a/migrations/2023-06-24-185942_aggegates_published_indexes/down.sql b/migrations/2023-06-24-185942_aggegates_published_indexes/down.sql index fa7f7d48f..840d54b01 100644 --- a/migrations/2023-06-24-185942_aggegates_published_indexes/down.sql +++ b/migrations/2023-06-24-185942_aggegates_published_indexes/down.sql @@ -1,2 +1,4 @@ -drop index idx_comment_aggregates_published; -drop index idx_community_aggregates_published; +DROP INDEX idx_comment_aggregates_published; + +DROP INDEX idx_community_aggregates_published; + diff --git a/migrations/2023-06-24-185942_aggegates_published_indexes/up.sql b/migrations/2023-06-24-185942_aggegates_published_indexes/up.sql index 42230af10..b7f9d30e6 100644 --- a/migrations/2023-06-24-185942_aggegates_published_indexes/up.sql +++ b/migrations/2023-06-24-185942_aggegates_published_indexes/up.sql @@ -1,4 +1,5 @@ -- Add indexes on published column (needed for hot_rank updates) +CREATE INDEX idx_community_aggregates_published ON community_aggregates (published DESC); + +CREATE INDEX idx_comment_aggregates_published ON comment_aggregates (published DESC); -create index idx_community_aggregates_published on community_aggregates (published desc); -create index idx_comment_aggregates_published on comment_aggregates (published desc); \ No newline at end of file diff --git a/migrations/2023-06-27-065106_add_ui_settings/down.sql b/migrations/2023-06-27-065106_add_ui_settings/down.sql index 51fa70467..9f56764d6 100644 --- a/migrations/2023-06-27-065106_add_ui_settings/down.sql +++ b/migrations/2023-06-27-065106_add_ui_settings/down.sql @@ -1,2 +1,6 @@ -alter table local_user drop column blur_nsfw; -alter table local_user drop column auto_expand; +ALTER TABLE local_user + DROP COLUMN blur_nsfw; + +ALTER TABLE local_user + DROP COLUMN auto_expand; + diff --git a/migrations/2023-06-27-065106_add_ui_settings/up.sql b/migrations/2023-06-27-065106_add_ui_settings/up.sql index 3c66c9c79..cff39601f 100644 --- a/migrations/2023-06-27-065106_add_ui_settings/up.sql +++ b/migrations/2023-06-27-065106_add_ui_settings/up.sql @@ -1,6 +1,8 @@ - -- Add the blur_nsfw to the local user table as a setting -alter table local_user add column blur_nsfw boolean not null default true; +ALTER TABLE local_user + ADD COLUMN blur_nsfw boolean NOT NULL DEFAULT TRUE; -- Add the auto_expand to the local user table as a setting -alter table local_user add column auto_expand boolean not null default false; +ALTER TABLE local_user + ADD COLUMN auto_expand boolean NOT NULL DEFAULT FALSE; + diff --git a/migrations/2023-07-04-153335_add_optimized_indexes/down.sql b/migrations/2023-07-04-153335_add_optimized_indexes/down.sql index 9b4996e36..e69f0493e 100644 --- a/migrations/2023-07-04-153335_add_optimized_indexes/down.sql +++ b/migrations/2023-07-04-153335_add_optimized_indexes/down.sql @@ -1,27 +1,46 @@ -- Drop the new indexes -drop index idx_person_admin; +DROP INDEX idx_person_admin; -drop index idx_post_aggregates_featured_local_score; -drop index idx_post_aggregates_featured_local_newest_comment_time; -drop index idx_post_aggregates_featured_local_newest_comment_time_necro; -drop index idx_post_aggregates_featured_local_hot; -drop index idx_post_aggregates_featured_local_active; -drop index idx_post_aggregates_featured_local_published; -drop index idx_post_aggregates_published; +DROP INDEX idx_post_aggregates_featured_local_score; -drop index idx_post_aggregates_featured_community_score; -drop index idx_post_aggregates_featured_community_newest_comment_time; -drop index idx_post_aggregates_featured_community_newest_comment_time_necro; -drop index idx_post_aggregates_featured_community_hot; -drop index idx_post_aggregates_featured_community_active; -drop index idx_post_aggregates_featured_community_published; +DROP INDEX idx_post_aggregates_featured_local_newest_comment_time; + +DROP INDEX idx_post_aggregates_featured_local_newest_comment_time_necro; + +DROP INDEX idx_post_aggregates_featured_local_hot; + +DROP INDEX idx_post_aggregates_featured_local_active; + +DROP INDEX idx_post_aggregates_featured_local_published; + +DROP INDEX idx_post_aggregates_published; + +DROP INDEX idx_post_aggregates_featured_community_score; + +DROP INDEX idx_post_aggregates_featured_community_newest_comment_time; + +DROP INDEX idx_post_aggregates_featured_community_newest_comment_time_necro; + +DROP INDEX idx_post_aggregates_featured_community_hot; + +DROP INDEX idx_post_aggregates_featured_community_active; + +DROP INDEX idx_post_aggregates_featured_community_published; -- Create single column indexes again -create index idx_post_aggregates_score on post_aggregates (score desc); -create index idx_post_aggregates_published on post_aggregates (published desc); -create index idx_post_aggregates_newest_comment_time on post_aggregates (newest_comment_time desc); -create index idx_post_aggregates_newest_comment_time_necro on post_aggregates (newest_comment_time_necro desc); -create index idx_post_aggregates_featured_community on post_aggregates (featured_community desc); -create index idx_post_aggregates_featured_local on post_aggregates (featured_local desc); -create index idx_post_aggregates_hot on post_aggregates (hot_rank desc); -create index idx_post_aggregates_active on post_aggregates (hot_rank_active desc); +CREATE INDEX idx_post_aggregates_score ON post_aggregates (score DESC); + +CREATE INDEX idx_post_aggregates_published ON post_aggregates (published DESC); + +CREATE INDEX idx_post_aggregates_newest_comment_time ON post_aggregates (newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_newest_comment_time_necro ON post_aggregates (newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_community ON post_aggregates (featured_community DESC); + +CREATE INDEX idx_post_aggregates_featured_local ON post_aggregates (featured_local DESC); + +CREATE INDEX idx_post_aggregates_hot ON post_aggregates (hot_rank DESC); + +CREATE INDEX idx_post_aggregates_active ON post_aggregates (hot_rank_active DESC); + diff --git a/migrations/2023-07-04-153335_add_optimized_indexes/up.sql b/migrations/2023-07-04-153335_add_optimized_indexes/up.sql index c55ecee9d..85c5827f2 100644 --- a/migrations/2023-07-04-153335_add_optimized_indexes/up.sql +++ b/migrations/2023-07-04-153335_add_optimized_indexes/up.sql @@ -1,32 +1,49 @@ -- Create an admin person index -create index if not exists idx_person_admin on person (admin); +CREATE INDEX IF NOT EXISTS idx_person_admin ON person (admin); -- Compound indexes, using featured_, then the other sorts, proved to be much faster -- Drop the old indexes -drop index idx_post_aggregates_score; -drop index idx_post_aggregates_published; -drop index idx_post_aggregates_newest_comment_time; -drop index idx_post_aggregates_newest_comment_time_necro; -drop index idx_post_aggregates_featured_community; -drop index idx_post_aggregates_featured_local; -drop index idx_post_aggregates_hot; -drop index idx_post_aggregates_active; +DROP INDEX idx_post_aggregates_score; + +DROP INDEX idx_post_aggregates_published; + +DROP INDEX idx_post_aggregates_newest_comment_time; + +DROP INDEX idx_post_aggregates_newest_comment_time_necro; + +DROP INDEX idx_post_aggregates_featured_community; + +DROP INDEX idx_post_aggregates_featured_local; + +DROP INDEX idx_post_aggregates_hot; + +DROP INDEX idx_post_aggregates_active; -- featured_local -create index idx_post_aggregates_featured_local_score on post_aggregates (featured_local desc, score desc); -create index idx_post_aggregates_featured_local_newest_comment_time on post_aggregates (featured_local desc, newest_comment_time desc); -create index idx_post_aggregates_featured_local_newest_comment_time_necro on post_aggregates (featured_local desc, newest_comment_time_necro desc); -create index idx_post_aggregates_featured_local_hot on post_aggregates (featured_local desc, hot_rank desc); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank_active desc); -create index idx_post_aggregates_featured_local_published on post_aggregates (featured_local desc, published desc); -create index idx_post_aggregates_published on post_aggregates (published desc); +CREATE INDEX idx_post_aggregates_featured_local_score ON post_aggregates (featured_local DESC, score DESC); + +CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time ON post_aggregates (featured_local DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time_necro ON post_aggregates (featured_local DESC, newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_local_hot ON post_aggregates (featured_local DESC, hot_rank DESC); + +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank_active DESC); + +CREATE INDEX idx_post_aggregates_featured_local_published ON post_aggregates (featured_local DESC, published DESC); + +CREATE INDEX idx_post_aggregates_published ON post_aggregates (published DESC); -- featured_community -create index idx_post_aggregates_featured_community_score on post_aggregates (featured_community desc, score desc); -create index idx_post_aggregates_featured_community_newest_comment_time on post_aggregates (featured_community desc, newest_comment_time desc); -create index idx_post_aggregates_featured_community_newest_comment_time_necro on post_aggregates (featured_community desc, newest_comment_time_necro desc); -create index idx_post_aggregates_featured_community_hot on post_aggregates (featured_community desc, hot_rank desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank_active desc); -create index idx_post_aggregates_featured_community_published on post_aggregates (featured_community desc, published desc); +CREATE INDEX idx_post_aggregates_featured_community_score ON post_aggregates (featured_community DESC, score DESC); +CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time ON post_aggregates (featured_community DESC, newest_comment_time DESC); + +CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time_necro ON post_aggregates (featured_community DESC, newest_comment_time_necro DESC); + +CREATE INDEX idx_post_aggregates_featured_community_hot ON post_aggregates (featured_community DESC, hot_rank DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank_active DESC); + +CREATE INDEX idx_post_aggregates_featured_community_published ON post_aggregates (featured_community DESC, published DESC); diff --git a/migrations/2023-07-05-000058_person-admin/down.sql b/migrations/2023-07-05-000058_person-admin/down.sql index b77e17475..9eba8f581 100644 --- a/migrations/2023-07-05-000058_person-admin/down.sql +++ b/migrations/2023-07-05-000058_person-admin/down.sql @@ -1,2 +1,4 @@ -drop index idx_person_admin; -create index idx_person_admin on person(admin); \ No newline at end of file +DROP INDEX idx_person_admin; + +CREATE INDEX idx_person_admin ON person (admin); + diff --git a/migrations/2023-07-05-000058_person-admin/up.sql b/migrations/2023-07-05-000058_person-admin/up.sql index c71052ec7..718848028 100644 --- a/migrations/2023-07-05-000058_person-admin/up.sql +++ b/migrations/2023-07-05-000058_person-admin/up.sql @@ -1,2 +1,7 @@ -drop index if exists idx_person_admin; -create index idx_person_admin on person(admin) where admin; -- allow quickly finding all admins (PersonView::admins) \ No newline at end of file +DROP INDEX IF EXISTS idx_person_admin; + +CREATE INDEX idx_person_admin ON person (admin) +WHERE + admin; + +-- allow quickly finding all admins (PersonView::admins) diff --git a/migrations/2023-07-06-151124_hot-rank-future/down.sql b/migrations/2023-07-06-151124_hot-rank-future/down.sql index b8f9a63f9..4816c616e 100644 --- a/migrations/2023-07-06-151124_hot-rank-future/down.sql +++ b/migrations/2023-07-06-151124_hot-rank-future/down.sql @@ -1,9 +1,9 @@ -CREATE OR REPLACE FUNCTION hot_rank(score numeric, published timestamp without time zone) +CREATE OR REPLACE FUNCTION hot_rank (score numeric, published timestamp without time zone) RETURNS integer AS $$ BEGIN -- hours_diff:=EXTRACT(EPOCH FROM (timezone('utc',now()) - published))/3600 - RETURN floor(10000 * log(greatest(1, score + 3)) / power(((EXTRACT(EPOCH FROM(timezone('utc', now()) - published)) / 3600) + 2), 1.8))::integer; + RETURN floor(10000 * log(greatest (1, score + 3)) / power(((EXTRACT(EPOCH FROM (timezone('utc', now()) - published)) / 3600) + 2), 1.8))::integer; END; $$ LANGUAGE plpgsql diff --git a/migrations/2023-07-06-151124_hot-rank-future/up.sql b/migrations/2023-07-06-151124_hot-rank-future/up.sql index 41baa673c..83b5f0f0b 100644 --- a/migrations/2023-07-06-151124_hot-rank-future/up.sql +++ b/migrations/2023-07-06-151124_hot-rank-future/up.sql @@ -1,11 +1,11 @@ -CREATE OR REPLACE FUNCTION hot_rank(score numeric, published timestamp without time zone) +CREATE OR REPLACE FUNCTION hot_rank (score numeric, published timestamp without time zone) RETURNS integer AS $$ DECLARE hours_diff numeric := EXTRACT(EPOCH FROM (timezone('utc', now()) - published)) / 3600; BEGIN IF (hours_diff > 0) THEN - RETURN floor(10000 * log(greatest(1, score + 3)) / power((hours_diff + 2), 1.8))::integer; + RETURN floor(10000 * log(greatest (1, score + 3)) / power((hours_diff + 2), 1.8))::integer; ELSE RETURN 0; END IF; diff --git a/migrations/2023-07-08-101154_fix_soft_delete_aggregates/down.sql b/migrations/2023-07-08-101154_fix_soft_delete_aggregates/down.sql index b9616dee7..d9fce66e3 100644 --- a/migrations/2023-07-08-101154_fix_soft_delete_aggregates/down.sql +++ b/migrations/2023-07-08-101154_fix_soft_delete_aggregates/down.sql @@ -1,105 +1,129 @@ -- 2023-06-19-120700_no_double_deletion/up.sql -create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) -RETURNS boolean -LANGUAGE plpgsql -as $$ - begin - IF (TG_OP = 'INSERT') THEN - return false; - end if; - - IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN - return true; - end if; - - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 'f' AND NEW.deleted = 't') OR - (OLD.removed = 'f' AND NEW.removed = 't') - ); -END $$; - --- 2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql -create or replace function was_restored_or_created(TG_OP text, OLD record, NEW record) +CREATE OR REPLACE FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record) RETURNS boolean LANGUAGE plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - return false; - end if; - + AS $$ +BEGIN IF (TG_OP = 'INSERT') THEN - return true; - end if; + RETURN FALSE; + END IF; + IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 'f' + AND NEW.deleted = 't') + OR (OLD.removed = 'f' + AND NEW.removed = 't')); +END +$$; - return TG_OP = 'UPDATE' AND ( - (OLD.deleted = 't' AND NEW.deleted = 'f') OR - (OLD.removed = 't' AND NEW.removed = 'f') - ); -END $$; +-- 2022-04-04-183652_update_community_aggregates_on_soft_delete/up.sql +CREATE OR REPLACE FUNCTION was_restored_or_created (TG_OP text, OLD record, NEW record) + RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + RETURN FALSE; + END IF; + IF (TG_OP = 'INSERT') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND ((OLD.deleted = 't' + AND NEW.deleted = 'f') + OR (OLD.removed = 't' + AND NEW.removed = 'f')); +END +$$; -- 2021-08-02-002342_comment_count_fixes/up.sql -create or replace function post_aggregates_comment_deleted() -returns trigger language plpgsql -as $$ -begin - IF NEW.deleted = TRUE THEN - update post_aggregates pa - set comments = comments - 1 - where pa.post_id = NEW.post_id; - ELSE - update post_aggregates pa - set comments = comments + 1 - where pa.post_id = NEW.post_id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_comment_deleted () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF NEW.deleted = TRUE THEN + UPDATE + post_aggregates pa + SET + comments = comments - 1 + WHERE + pa.post_id = NEW.post_id; + ELSE + UPDATE + post_aggregates pa + SET + comments = comments + 1 + WHERE + pa.post_id = NEW.post_id; + END IF; + RETURN NULL; +END +$$; -create trigger post_aggregates_comment_set_deleted -after update of deleted on comment -for each row -execute procedure post_aggregates_comment_deleted(); +CREATE TRIGGER post_aggregates_comment_set_deleted + AFTER UPDATE OF deleted ON comment + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_comment_deleted (); -create or replace function post_aggregates_comment_count() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set comments = comments + 1, - newest_comment_time = NEW.published - where pa.post_id = NEW.post_id; - - -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time_necro = NEW.published - from post p - where pa.post_id = p.id - and pa.post_id = NEW.post_id - -- Fix issue with being able to necro-bump your own post - and NEW.creator_id != p.creator_id - and pa.published > ('now'::timestamp - '2 days'::interval); - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - ELSIF (TG_OP = 'UPDATE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set comments = comments - 1 - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1, + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id; + -- A 2 day necro-bump limit + UPDATE + post_aggregates pa + SET + newest_comment_time_necro = NEW.published + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = NEW.post_id + -- Fix issue with being able to necro-bump your own post + AND NEW.creator_id != p.creator_id + AND pa.published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + ELSIF (TG_OP = 'UPDATE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + comments = comments - 1 + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -- 2020-12-10-152350_create_post_aggregates/up.sql -create or replace trigger post_aggregates_comment_count -after insert or delete on comment -for each row -execute procedure post_aggregates_comment_count(); +CREATE OR REPLACE TRIGGER post_aggregates_comment_count + AFTER INSERT OR DELETE ON comment + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_comment_count (); + diff --git a/migrations/2023-07-08-101154_fix_soft_delete_aggregates/up.sql b/migrations/2023-07-08-101154_fix_soft_delete_aggregates/up.sql index abc89d283..2884f934f 100644 --- a/migrations/2023-07-08-101154_fix_soft_delete_aggregates/up.sql +++ b/migrations/2023-07-08-101154_fix_soft_delete_aggregates/up.sql @@ -1,81 +1,104 @@ -- Fix for duplicated decrementations when both `deleted` and `removed` fields are set subsequently -create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) -RETURNS boolean -LANGUAGE plpgsql -as $$ - begin - IF (TG_OP = 'INSERT') THEN - return false; - end if; - - IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN - return true; - end if; - - return TG_OP = 'UPDATE' AND OLD.deleted = 'f' AND OLD.removed = 'f' AND ( - NEW.deleted = 't' OR NEW.removed = 't' - ); -END $$; - -create or replace function was_restored_or_created(TG_OP text, OLD record, NEW record) +CREATE OR REPLACE FUNCTION was_removed_or_deleted (TG_OP text, OLD record, NEW record) RETURNS boolean LANGUAGE plpgsql -as $$ -begin - IF (TG_OP = 'DELETE') THEN - return false; - end if; - + AS $$ +BEGIN IF (TG_OP = 'INSERT') THEN - return true; - end if; + RETURN FALSE; + END IF; + IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND OLD.deleted = 'f' + AND OLD.removed = 'f' + AND (NEW.deleted = 't' + OR NEW.removed = 't'); +END +$$; - return TG_OP = 'UPDATE' AND NEW.deleted = 'f' AND NEW.removed = 'f' AND ( - OLD.deleted = 't' OR OLD.removed = 't' - ); -END $$; +CREATE OR REPLACE FUNCTION was_restored_or_created (TG_OP text, OLD record, NEW record) + RETURNS boolean + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'DELETE') THEN + RETURN FALSE; + END IF; + IF (TG_OP = 'INSERT') THEN + RETURN TRUE; + END IF; + RETURN TG_OP = 'UPDATE' + AND NEW.deleted = 'f' + AND NEW.removed = 'f' + AND (OLD.deleted = 't' + OR OLD.removed = 't'); +END +$$; -- Fix for post's comment count not updating after setting `removed` to 't' -drop trigger if exists post_aggregates_comment_set_deleted on comment; -drop function post_aggregates_comment_deleted(); +DROP TRIGGER IF EXISTS post_aggregates_comment_set_deleted ON comment; -create or replace function post_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin +DROP FUNCTION post_aggregates_comment_deleted (); + +CREATE OR REPLACE FUNCTION post_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN -- Check for post existence - it may not exist anymore IF TG_OP = 'INSERT' OR EXISTS ( - select 1 from post p where p.id = OLD.post_id - ) THEN - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update post_aggregates pa - set comments = comments + 1 where pa.post_id = NEW.post_id; - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update post_aggregates pa - set comments = comments - 1 where pa.post_id = OLD.post_id; + SELECT + 1 + FROM + post p + WHERE + p.id = OLD.post_id) THEN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + post_aggregates pa + SET + comments = comments + 1 + WHERE + pa.post_id = NEW.post_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + post_aggregates pa + SET + comments = comments - 1 + WHERE + pa.post_id = OLD.post_id; END IF; END IF; - IF TG_OP = 'INSERT' THEN - update post_aggregates pa - set newest_comment_time = NEW.published - where pa.post_id = NEW.post_id; - + UPDATE + post_aggregates pa + SET + newest_comment_time = NEW.published + WHERE + pa.post_id = NEW.post_id; -- A 2 day necro-bump limit - update post_aggregates pa - set newest_comment_time_necro = NEW.published - from post p - where pa.post_id = p.id - and pa.post_id = NEW.post_id - -- Fix issue with being able to necro-bump your own post - and NEW.creator_id != p.creator_id - and pa.published > ('now'::timestamp - '2 days'::interval); + UPDATE + post_aggregates pa + SET + newest_comment_time_necro = NEW.published + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = NEW.post_id + -- Fix issue with being able to necro-bump your own post + AND NEW.creator_id != p.creator_id + AND pa.published > ('now'::timestamp - '2 days'::interval); END IF; + RETURN NULL; +END +$$; - return null; -end $$; +CREATE OR REPLACE TRIGGER post_aggregates_comment_count + AFTER INSERT OR DELETE OR UPDATE OF removed, + deleted ON comment + FOR EACH ROW + EXECUTE PROCEDURE post_aggregates_comment_count (); -create or replace trigger post_aggregates_comment_count - after insert or delete or update of removed, deleted on comment - for each row -execute procedure post_aggregates_comment_count(); \ No newline at end of file diff --git a/migrations/2023-07-10-075550_add-infinite-scroll-setting/down.sql b/migrations/2023-07-10-075550_add-infinite-scroll-setting/down.sql index 66ff507d9..721922db0 100644 --- a/migrations/2023-07-10-075550_add-infinite-scroll-setting/down.sql +++ b/migrations/2023-07-10-075550_add-infinite-scroll-setting/down.sql @@ -1 +1,3 @@ -alter table local_user drop column infinite_scroll_enabled; +ALTER TABLE local_user + DROP COLUMN infinite_scroll_enabled; + diff --git a/migrations/2023-07-10-075550_add-infinite-scroll-setting/up.sql b/migrations/2023-07-10-075550_add-infinite-scroll-setting/up.sql index 905bc7109..b435e2e27 100644 --- a/migrations/2023-07-10-075550_add-infinite-scroll-setting/up.sql +++ b/migrations/2023-07-10-075550_add-infinite-scroll-setting/up.sql @@ -1 +1,3 @@ -alter table local_user add column infinite_scroll_enabled boolean default false not null; +ALTER TABLE local_user + ADD COLUMN infinite_scroll_enabled boolean DEFAULT FALSE NOT NULL; + diff --git a/migrations/2023-07-11-084714_receive_activity_table/down.sql b/migrations/2023-07-11-084714_receive_activity_table/down.sql index ea4f4d4a3..188b4afa4 100644 --- a/migrations/2023-07-11-084714_receive_activity_table/down.sql +++ b/migrations/2023-07-11-084714_receive_activity_table/down.sql @@ -1,21 +1,28 @@ -create table activity ( - id serial primary key, - data jsonb not null, - local boolean not null default true, - published timestamp not null default now(), +CREATE TABLE activity ( + id serial PRIMARY KEY, + data jsonb NOT NULL, + local boolean NOT NULL DEFAULT TRUE, + published timestamp NOT NULL DEFAULT now(), updated timestamp, - ap_id text not null, - sensitive boolean not null default true + ap_id text NOT NULL, + sensitive boolean NOT NULL DEFAULT TRUE ); -insert into activity(ap_id, data, sensitive, published) - select ap_id, data, sensitive, published - from sent_activity - order by id desc - limit 100000; +INSERT INTO activity (ap_id, data, sensitive, published) +SELECT + ap_id, + data, + sensitive, + published +FROM + sent_activity +ORDER BY + id DESC +LIMIT 100000; -- We cant copy received_activity entries back into activities table because we dont have data -- which is mandatory. +DROP TABLE sent_activity; + +DROP TABLE received_activity; -drop table sent_activity; -drop table received_activity; \ No newline at end of file diff --git a/migrations/2023-07-11-084714_receive_activity_table/up.sql b/migrations/2023-07-11-084714_receive_activity_table/up.sql index c6b30b7b7..4d723491a 100644 --- a/migrations/2023-07-11-084714_receive_activity_table/up.sql +++ b/migrations/2023-07-11-084714_receive_activity_table/up.sql @@ -1,35 +1,48 @@ -- outgoing activities, need to be stored to be later server over http -- we change data column from jsonb to json for decreased size -- https://stackoverflow.com/a/22910602 -create table sent_activity ( - id bigserial primary key, - ap_id text unique not null, - data json not null, - sensitive boolean not null, - published timestamp not null default now() +CREATE TABLE sent_activity ( + id bigserial PRIMARY KEY, + ap_id text UNIQUE NOT NULL, + data json NOT NULL, + sensitive boolean NOT NULL, + published timestamp NOT NULL DEFAULT now() ); -- incoming activities, we only need the id to avoid processing the same activity multiple times -create table received_activity ( - id bigserial primary key, - ap_id text unique not null, - published timestamp not null default now() +CREATE TABLE received_activity ( + id bigserial PRIMARY KEY, + ap_id text UNIQUE NOT NULL, + published timestamp NOT NULL DEFAULT now() ); -- copy sent activities to new table. only copy last 100k for faster migration -insert into sent_activity(ap_id, data, sensitive, published) - select ap_id, data, sensitive, published - from activity - where local = true - order by id desc - limit 100000; +INSERT INTO sent_activity (ap_id, data, sensitive, published) +SELECT + ap_id, + data, + sensitive, + published +FROM + activity +WHERE + local = TRUE +ORDER BY + id DESC +LIMIT 100000; -- copy received activities to new table. only last 1m for faster migration -insert into received_activity(ap_id, published) - select ap_id, published - from activity - where local = false - order by id desc - limit 1000000; +INSERT INTO received_activity (ap_id, published) +SELECT + ap_id, + published +FROM + activity +WHERE + local = FALSE +ORDER BY + id DESC +LIMIT 1000000; + +DROP TABLE activity; -drop table activity; diff --git a/migrations/2023-07-14-154840_add_optimized_indexes_published/down.sql b/migrations/2023-07-14-154840_add_optimized_indexes_published/down.sql index 5661a3146..7bc306f91 100644 --- a/migrations/2023-07-14-154840_add_optimized_indexes_published/down.sql +++ b/migrations/2023-07-14-154840_add_optimized_indexes_published/down.sql @@ -1,26 +1,40 @@ -- Drop the new indexes -drop index idx_post_aggregates_featured_local_most_comments; -drop index idx_post_aggregates_featured_local_hot; -drop index idx_post_aggregates_featured_local_active; -drop index idx_post_aggregates_featured_local_score; -drop index idx_post_aggregates_featured_community_hot; -drop index idx_post_aggregates_featured_community_active; -drop index idx_post_aggregates_featured_community_score; -drop index idx_post_aggregates_featured_community_most_comments; -drop index idx_comment_aggregates_hot; -drop index idx_comment_aggregates_score; +DROP INDEX idx_post_aggregates_featured_local_most_comments; + +DROP INDEX idx_post_aggregates_featured_local_hot; + +DROP INDEX idx_post_aggregates_featured_local_active; + +DROP INDEX idx_post_aggregates_featured_local_score; + +DROP INDEX idx_post_aggregates_featured_community_hot; + +DROP INDEX idx_post_aggregates_featured_community_active; + +DROP INDEX idx_post_aggregates_featured_community_score; + +DROP INDEX idx_post_aggregates_featured_community_most_comments; + +DROP INDEX idx_comment_aggregates_hot; + +DROP INDEX idx_comment_aggregates_score; -- Add the old ones back in -- featured_local -create index idx_post_aggregates_featured_local_hot on post_aggregates (featured_local desc, hot_rank desc); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank_active desc); -create index idx_post_aggregates_featured_local_score on post_aggregates (featured_local desc, score desc); +CREATE INDEX idx_post_aggregates_featured_local_hot ON post_aggregates (featured_local DESC, hot_rank DESC); + +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank_active DESC); + +CREATE INDEX idx_post_aggregates_featured_local_score ON post_aggregates (featured_local DESC, score DESC); -- featured_community -create index idx_post_aggregates_featured_community_hot on post_aggregates (featured_community desc, hot_rank desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank_active desc); -create index idx_post_aggregates_featured_community_score on post_aggregates (featured_community desc, score desc); +CREATE INDEX idx_post_aggregates_featured_community_hot ON post_aggregates (featured_community DESC, hot_rank DESC); -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank desc); -create index idx_comment_aggregates_score on comment_aggregates (score desc); +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank_active DESC); + +CREATE INDEX idx_post_aggregates_featured_community_score ON post_aggregates (featured_community DESC, score DESC); + +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank DESC); + +CREATE INDEX idx_comment_aggregates_score ON comment_aggregates (score DESC); diff --git a/migrations/2023-07-14-154840_add_optimized_indexes_published/up.sql b/migrations/2023-07-14-154840_add_optimized_indexes_published/up.sql index 94e426fc7..728ca38d4 100644 --- a/migrations/2023-07-14-154840_add_optimized_indexes_published/up.sql +++ b/migrations/2023-07-14-154840_add_optimized_indexes_published/up.sql @@ -1,30 +1,42 @@ -- Drop the old indexes -drop index idx_post_aggregates_featured_local_hot; -drop index idx_post_aggregates_featured_local_active; -drop index idx_post_aggregates_featured_local_score; -drop index idx_post_aggregates_featured_community_hot; -drop index idx_post_aggregates_featured_community_active; -drop index idx_post_aggregates_featured_community_score; -drop index idx_comment_aggregates_hot; -drop index idx_comment_aggregates_score; +DROP INDEX idx_post_aggregates_featured_local_hot; + +DROP INDEX idx_post_aggregates_featured_local_active; + +DROP INDEX idx_post_aggregates_featured_local_score; + +DROP INDEX idx_post_aggregates_featured_community_hot; + +DROP INDEX idx_post_aggregates_featured_community_active; + +DROP INDEX idx_post_aggregates_featured_community_score; + +DROP INDEX idx_comment_aggregates_hot; + +DROP INDEX idx_comment_aggregates_score; -- Add a published desc, to the end of the hot and active ranks - -- Add missing most comments index -create index idx_post_aggregates_featured_local_most_comments on post_aggregates (featured_local desc, comments desc, published desc); -create index idx_post_aggregates_featured_community_most_comments on post_aggregates (featured_community desc, comments desc, published desc); +CREATE INDEX idx_post_aggregates_featured_local_most_comments ON post_aggregates (featured_local DESC, comments DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_community_most_comments ON post_aggregates (featured_community DESC, comments DESC, published DESC); -- featured_local -create index idx_post_aggregates_featured_local_hot on post_aggregates (featured_local desc, hot_rank desc, published desc); -create index idx_post_aggregates_featured_local_active on post_aggregates (featured_local desc, hot_rank_active desc, published desc); -create index idx_post_aggregates_featured_local_score on post_aggregates (featured_local desc, score desc, published desc); +CREATE INDEX idx_post_aggregates_featured_local_hot ON post_aggregates (featured_local DESC, hot_rank DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_local_active ON post_aggregates (featured_local DESC, hot_rank_active DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_local_score ON post_aggregates (featured_local DESC, score DESC, published DESC); -- featured_community -create index idx_post_aggregates_featured_community_hot on post_aggregates (featured_community desc, hot_rank desc, published desc); -create index idx_post_aggregates_featured_community_active on post_aggregates (featured_community desc, hot_rank_active desc, published desc); -create index idx_post_aggregates_featured_community_score on post_aggregates (featured_community desc, score desc, published desc); +CREATE INDEX idx_post_aggregates_featured_community_hot ON post_aggregates (featured_community DESC, hot_rank DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_community_active ON post_aggregates (featured_community DESC, hot_rank_active DESC, published DESC); + +CREATE INDEX idx_post_aggregates_featured_community_score ON post_aggregates (featured_community DESC, score DESC, published DESC); -- Fixing some comment aggregates ones -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank desc, published desc); -create index idx_comment_aggregates_score on comment_aggregates (score desc, published desc); +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank DESC, published DESC); + +CREATE INDEX idx_comment_aggregates_score ON comment_aggregates (score DESC, published DESC); diff --git a/migrations/2023-07-14-215339_aggregates_nonzero_indexes/down.sql b/migrations/2023-07-14-215339_aggregates_nonzero_indexes/down.sql index 3e247b58c..658853eb3 100644 --- a/migrations/2023-07-14-215339_aggregates_nonzero_indexes/down.sql +++ b/migrations/2023-07-14-215339_aggregates_nonzero_indexes/down.sql @@ -1,4 +1,7 @@ -- This file should undo anything in `up.sql` DROP INDEX idx_community_aggregates_nonzero_hotrank; + DROP INDEX idx_comment_aggregates_nonzero_hotrank; -DROP INDEX idx_post_aggregates_nonzero_hotrank; \ No newline at end of file + +DROP INDEX idx_post_aggregates_nonzero_hotrank; + diff --git a/migrations/2023-07-14-215339_aggregates_nonzero_indexes/up.sql b/migrations/2023-07-14-215339_aggregates_nonzero_indexes/up.sql index 2d3cd3b29..d51aa0dc4 100644 --- a/migrations/2023-07-14-215339_aggregates_nonzero_indexes/up.sql +++ b/migrations/2023-07-14-215339_aggregates_nonzero_indexes/up.sql @@ -1,4 +1,13 @@ -- Your SQL goes here -CREATE INDEX idx_community_aggregates_nonzero_hotrank ON community_aggregates (published) WHERE hot_rank != 0; -CREATE INDEX idx_comment_aggregates_nonzero_hotrank ON comment_aggregates (published) WHERE hot_rank != 0; -CREATE INDEX idx_post_aggregates_nonzero_hotrank ON post_aggregates (published DESC) WHERE hot_rank != 0 OR hot_rank_active != 0; \ No newline at end of file +CREATE INDEX idx_community_aggregates_nonzero_hotrank ON community_aggregates (published) +WHERE + hot_rank != 0; + +CREATE INDEX idx_comment_aggregates_nonzero_hotrank ON comment_aggregates (published) +WHERE + hot_rank != 0; + +CREATE INDEX idx_post_aggregates_nonzero_hotrank ON post_aggregates (published DESC) +WHERE + hot_rank != 0 OR hot_rank_active != 0; + diff --git a/migrations/2023-07-18-082614_post_aggregates_community_id/down.sql b/migrations/2023-07-18-082614_post_aggregates_community_id/down.sql index 91e2dc862..8e2214656 100644 --- a/migrations/2023-07-18-082614_post_aggregates_community_id/down.sql +++ b/migrations/2023-07-18-082614_post_aggregates_community_id/down.sql @@ -1,20 +1,21 @@ -- This file should undo anything in `up.sql` - -CREATE OR REPLACE FUNCTION post_aggregates_post() - RETURNS trigger +CREATE OR REPLACE FUNCTION post_aggregates_post () + RETURNS TRIGGER LANGUAGE plpgsql -AS -$$ + AS $$ BEGIN IF (TG_OP = 'INSERT') THEN INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro) - VALUES (NEW.id, NEW.published, NEW.published, NEW.published); + VALUES (NEW.id, NEW.published, NEW.published, NEW.published); ELSIF (TG_OP = 'DELETE') THEN - DELETE FROM post_aggregates WHERE post_id = OLD.id; + DELETE FROM post_aggregates + WHERE post_id = OLD.id; END IF; RETURN NULL; END $$; -ALTER TABLE post_aggregates DROP COLUMN community_id, DROP COLUMN creator_id; +ALTER TABLE post_aggregates + DROP COLUMN community_id, + DROP COLUMN creator_id; diff --git a/migrations/2023-07-18-082614_post_aggregates_community_id/up.sql b/migrations/2023-07-18-082614_post_aggregates_community_id/up.sql index f28701da0..d909ce022 100644 --- a/migrations/2023-07-18-082614_post_aggregates_community_id/up.sql +++ b/migrations/2023-07-18-082614_post_aggregates_community_id/up.sql @@ -3,33 +3,33 @@ ALTER TABLE post_aggregates ADD COLUMN community_id integer REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE, ADD COLUMN creator_id integer REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE; -CREATE OR REPLACE FUNCTION post_aggregates_post() - RETURNS trigger +CREATE OR REPLACE FUNCTION post_aggregates_post () + RETURNS TRIGGER LANGUAGE plpgsql -AS -$$ + AS $$ BEGIN IF (TG_OP = 'INSERT') THEN - INSERT INTO post_aggregates (post_id, - published, - newest_comment_time, - newest_comment_time_necro, - community_id, - creator_id) - VALUES (NEW.id, NEW.published, NEW.published, NEW.published, NEW.community_id, NEW.creator_id); + INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro, community_id, creator_id) + VALUES (NEW.id, NEW.published, NEW.published, NEW.published, NEW.community_id, NEW.creator_id); ELSIF (TG_OP = 'DELETE') THEN - DELETE FROM post_aggregates WHERE post_id = OLD.id; + DELETE FROM post_aggregates + WHERE post_id = OLD.id; END IF; RETURN NULL; END $$; -UPDATE post_aggregates -SET community_id=post.community_id, - creator_id=post.creator_id -FROM post -WHERE post.id = post_aggregates.post_id; +UPDATE + post_aggregates +SET + community_id = post.community_id, + creator_id = post.creator_id +FROM + post +WHERE + post.id = post_aggregates.post_id; ALTER TABLE post_aggregates ALTER COLUMN community_id SET NOT NULL, - ALTER COLUMN creator_id SET NOT NULL; \ No newline at end of file + ALTER COLUMN creator_id SET NOT NULL; + diff --git a/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/down.sql b/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/down.sql index 9f784c067..f7cdf93ea 100644 --- a/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/down.sql +++ b/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/down.sql @@ -1,4 +1,6 @@ -drop index idx_comment_aggregates_hot, idx_comment_aggregates_score; +DROP INDEX idx_comment_aggregates_hot, idx_comment_aggregates_score; + +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank DESC, published DESC); + +CREATE INDEX idx_comment_aggregates_score ON comment_aggregates (score DESC, published DESC); -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank desc, published desc); -create index idx_comment_aggregates_score on comment_aggregates (score desc, published desc); diff --git a/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/up.sql b/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/up.sql index 02eff3ed2..94ad1cc66 100644 --- a/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/up.sql +++ b/migrations/2023-07-19-163511_comment_sort_hot_rank_then_score/up.sql @@ -1,10 +1,10 @@ -- Alter the comment_aggregates hot sort to sort by score after hot_rank. --- Reason being, is that hot_ranks go to zero after a few days, +-- Reason being, is that hot_ranks go to zero after a few days, -- and then comments should be sorted by score, not published. +DROP INDEX idx_comment_aggregates_hot, idx_comment_aggregates_score; -drop index idx_comment_aggregates_hot, idx_comment_aggregates_score; - -create index idx_comment_aggregates_hot on comment_aggregates (hot_rank desc, score desc); +CREATE INDEX idx_comment_aggregates_hot ON comment_aggregates (hot_rank DESC, score DESC); -- Remove published from this sort, its pointless -create index idx_comment_aggregates_score on comment_aggregates (score desc); +CREATE INDEX idx_comment_aggregates_score ON comment_aggregates (score DESC); + diff --git a/migrations/2023-07-24-232635_trigram-index/up.sql b/migrations/2023-07-24-232635_trigram-index/up.sql index ed648b6e5..4875d2801 100644 --- a/migrations/2023-07-24-232635_trigram-index/up.sql +++ b/migrations/2023-07-24-232635_trigram-index/up.sql @@ -1,10 +1,10 @@ CREATE EXTENSION IF NOT EXISTS pg_trgm; -CREATE INDEX IF NOT EXISTS idx_comment_content_trigram ON comment USING gin(content gin_trgm_ops); +CREATE INDEX IF NOT EXISTS idx_comment_content_trigram ON comment USING gin (content gin_trgm_ops); -CREATE INDEX IF NOT EXISTS idx_post_trigram ON post USING gin(name gin_trgm_ops, body gin_trgm_ops); +CREATE INDEX IF NOT EXISTS idx_post_trigram ON post USING gin (name gin_trgm_ops, body gin_trgm_ops); -CREATE INDEX IF NOT EXISTS idx_person_trigram ON person USING gin(name gin_trgm_ops, display_name gin_trgm_ops); +CREATE INDEX IF NOT EXISTS idx_person_trigram ON person USING gin (name gin_trgm_ops, display_name gin_trgm_ops); -CREATE INDEX IF NOT EXISTS idx_community_trigram ON community USING gin(name gin_trgm_ops, title gin_trgm_ops); +CREATE INDEX IF NOT EXISTS idx_community_trigram ON community USING gin (name gin_trgm_ops, title gin_trgm_ops); diff --git a/migrations/2023-07-26-000217_create_controversial_indexes/down.sql b/migrations/2023-07-26-000217_create_controversial_indexes/down.sql index a355546d1..f4c5b4a18 100644 --- a/migrations/2023-07-26-000217_create_controversial_indexes/down.sql +++ b/migrations/2023-07-26-000217_create_controversial_indexes/down.sql @@ -1,63 +1,115 @@ -- Update comment_aggregates_score trigger function to exclude controversy_rank update -create or replace function comment_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update comment_aggregates ca - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end - where ca.comment_id = NEW.comment_id; - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to comment because that comment may not exist anymore - update comment_aggregates ca - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end - from comment c - where ca.comment_id = c.id - and ca.comment_id = OLD.comment_id; - - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION comment_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + comment_aggregates ca + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + ca.comment_id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to comment because that comment may not exist anymore + UPDATE + comment_aggregates ca + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END + FROM + comment c + WHERE + ca.comment_id = c.id + AND ca.comment_id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; -- Update post_aggregates_score trigger function to exclude controversy_rank update -create or replace function post_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end - where pa.post_id = NEW.post_id; - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END + WHERE + pa.post_id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -- Drop the indexes -drop index if exists idx_post_aggregates_featured_local_controversy; -drop index if exists idx_post_aggregates_featured_community_controversy; -drop index if exists idx_comment_aggregates_controversy; +DROP INDEX IF EXISTS idx_post_aggregates_featured_local_controversy; + +DROP INDEX IF EXISTS idx_post_aggregates_featured_community_controversy; + +DROP INDEX IF EXISTS idx_comment_aggregates_controversy; -- Remove the added columns from the tables -alter table post_aggregates drop column controversy_rank; -alter table comment_aggregates drop column controversy_rank; +ALTER TABLE post_aggregates + DROP COLUMN controversy_rank; + +ALTER TABLE comment_aggregates + DROP COLUMN controversy_rank; -- Remove function -drop function controversy_rank(numeric, numeric); +DROP FUNCTION controversy_rank (numeric, numeric); diff --git a/migrations/2023-07-26-000217_create_controversial_indexes/up.sql b/migrations/2023-07-26-000217_create_controversial_indexes/up.sql index f50a706bc..eb1d712ed 100644 --- a/migrations/2023-07-26-000217_create_controversial_indexes/up.sql +++ b/migrations/2023-07-26-000217_create_controversial_indexes/up.sql @@ -1,97 +1,184 @@ -- Need to add immutable to the controversy_rank function in order to index by it - -- Controversy Rank: -- if downvotes <= 0 or upvotes <= 0: --- 0 +-- 0 -- else: --- (upvotes + downvotes) * min(upvotes, downvotes) / max(upvotes, downvotes) -create or replace function controversy_rank(upvotes numeric, downvotes numeric) -returns float as $$ -begin - if downvotes <= 0 or upvotes <= 0 then - return 0; - else - return (upvotes + downvotes) * - case when upvotes > downvotes - then downvotes::float / upvotes::float - else upvotes::float / downvotes::float - end; - end if; -end; $$ +-- (upvotes + downvotes) * min(upvotes, downvotes) / max(upvotes, downvotes) +CREATE OR REPLACE FUNCTION controversy_rank (upvotes numeric, downvotes numeric) + RETURNS float + AS $$ +BEGIN + IF downvotes <= 0 OR upvotes <= 0 THEN + RETURN 0; + ELSE + RETURN (upvotes + downvotes) * CASE WHEN upvotes > downvotes THEN + downvotes::float / upvotes::float + ELSE + upvotes::float / downvotes::float + END; + END IF; +END; +$$ LANGUAGE plpgsql IMMUTABLE; -- Aggregates -alter table post_aggregates add column controversy_rank float not null default 0; -alter table comment_aggregates add column controversy_rank float not null default 0; +ALTER TABLE post_aggregates + ADD COLUMN controversy_rank float NOT NULL DEFAULT 0; + +ALTER TABLE comment_aggregates + ADD COLUMN controversy_rank float NOT NULL DEFAULT 0; -- Populate them initially -- Note: After initial population, these are updated with vote triggers -update post_aggregates set controversy_rank = controversy_rank(upvotes::numeric, downvotes::numeric); -update comment_aggregates set controversy_rank = controversy_rank(upvotes::numeric, downvotes::numeric); +UPDATE + post_aggregates +SET + controversy_rank = controversy_rank (upvotes::numeric, downvotes::numeric); + +UPDATE + comment_aggregates +SET + controversy_rank = controversy_rank (upvotes::numeric, downvotes::numeric); -- Create single column indexes -create index idx_post_aggregates_featured_local_controversy on post_aggregates (featured_local desc, controversy_rank desc); -create index idx_post_aggregates_featured_community_controversy on post_aggregates (featured_community desc, controversy_rank desc); -create index idx_comment_aggregates_controversy on comment_aggregates (controversy_rank desc); +CREATE INDEX idx_post_aggregates_featured_local_controversy ON post_aggregates (featured_local DESC, controversy_rank DESC); + +CREATE INDEX idx_post_aggregates_featured_community_controversy ON post_aggregates (featured_community DESC, controversy_rank DESC); + +CREATE INDEX idx_comment_aggregates_controversy ON comment_aggregates (controversy_rank DESC); -- Update post_aggregates_score trigger function to include controversy_rank update -create or replace function post_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update post_aggregates pa - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end, - controversy_rank = controversy_rank(pa.upvotes + case when NEW.score = 1 then 1 else 0 end::numeric, - pa.downvotes + case when NEW.score = -1 then 1 else 0 end::numeric) - where pa.post_id = NEW.post_id; - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to post because that post may not exist anymore - update post_aggregates pa - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end, - controversy_rank = controversy_rank(pa.upvotes + case when NEW.score = 1 then 1 else 0 end::numeric, - pa.downvotes + case when NEW.score = -1 then 1 else 0 end::numeric) - from post p - where pa.post_id = p.id - and pa.post_id = OLD.post_id; - - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION post_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + post_aggregates pa + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END, + controversy_rank = controversy_rank (pa.upvotes + CASE WHEN NEW.score = 1 THEN + 1 + ELSE + 0 + END::numeric, pa.downvotes + CASE WHEN NEW.score = - 1 THEN + 1 + ELSE + 0 + END::numeric) + WHERE + pa.post_id = NEW.post_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + UPDATE + post_aggregates pa + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END, + controversy_rank = controversy_rank (pa.upvotes + CASE WHEN NEW.score = 1 THEN + 1 + ELSE + 0 + END::numeric, pa.downvotes + CASE WHEN NEW.score = - 1 THEN + 1 + ELSE + 0 + END::numeric) + FROM + post p + WHERE + pa.post_id = p.id + AND pa.post_id = OLD.post_id; + END IF; + RETURN NULL; +END +$$; -- Update comment_aggregates_score trigger function to include controversy_rank update -create or replace function comment_aggregates_score() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - update comment_aggregates ca - set score = score + NEW.score, - upvotes = case when NEW.score = 1 then upvotes + 1 else upvotes end, - downvotes = case when NEW.score = -1 then downvotes + 1 else downvotes end, - controversy_rank = controversy_rank(ca.upvotes + case when NEW.score = 1 then 1 else 0 end::numeric, - ca.downvotes + case when NEW.score = -1 then 1 else 0 end::numeric) - where ca.comment_id = NEW.comment_id; - - ELSIF (TG_OP = 'DELETE') THEN - -- Join to comment because that comment may not exist anymore - update comment_aggregates ca - set score = score - OLD.score, - upvotes = case when OLD.score = 1 then upvotes - 1 else upvotes end, - downvotes = case when OLD.score = -1 then downvotes - 1 else downvotes end, - controversy_rank = controversy_rank(ca.upvotes + case when NEW.score = 1 then 1 else 0 end::numeric, - ca.downvotes + case when NEW.score = -1 then 1 else 0 end::numeric) - from comment c - where ca.comment_id = c.id - and ca.comment_id = OLD.comment_id; - - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION comment_aggregates_score () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + UPDATE + comment_aggregates ca + SET + score = score + NEW.score, + upvotes = CASE WHEN NEW.score = 1 THEN + upvotes + 1 + ELSE + upvotes + END, + downvotes = CASE WHEN NEW.score = - 1 THEN + downvotes + 1 + ELSE + downvotes + END, + controversy_rank = controversy_rank (ca.upvotes + CASE WHEN NEW.score = 1 THEN + 1 + ELSE + 0 + END::numeric, ca.downvotes + CASE WHEN NEW.score = - 1 THEN + 1 + ELSE + 0 + END::numeric) + WHERE + ca.comment_id = NEW.comment_id; + ELSIF (TG_OP = 'DELETE') THEN + -- Join to comment because that comment may not exist anymore + UPDATE + comment_aggregates ca + SET + score = score - OLD.score, + upvotes = CASE WHEN OLD.score = 1 THEN + upvotes - 1 + ELSE + upvotes + END, + downvotes = CASE WHEN OLD.score = - 1 THEN + downvotes - 1 + ELSE + downvotes + END, + controversy_rank = controversy_rank (ca.upvotes + CASE WHEN NEW.score = 1 THEN + 1 + ELSE + 0 + END::numeric, ca.downvotes + CASE WHEN NEW.score = - 1 THEN + 1 + ELSE + 0 + END::numeric) + FROM + comment c + WHERE + ca.comment_id = c.id + AND ca.comment_id = OLD.comment_id; + END IF; + RETURN NULL; +END +$$; diff --git a/migrations/2023-07-26-222023_site-aggregates-one/down.sql b/migrations/2023-07-26-222023_site-aggregates-one/down.sql index f384785f4..90dbbd7f1 100644 --- a/migrations/2023-07-26-222023_site-aggregates-one/down.sql +++ b/migrations/2023-07-26-222023_site-aggregates-one/down.sql @@ -1,11 +1,16 @@ -create or replace function site_aggregates_site() -returns trigger language plpgsql -as $$ -begin - IF (TG_OP = 'INSERT') THEN - insert into site_aggregates (site_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from site_aggregates where site_id = OLD.id; - END IF; - return null; -end $$; \ No newline at end of file +CREATE OR REPLACE FUNCTION site_aggregates_site () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (TG_OP = 'INSERT') THEN + INSERT INTO site_aggregates (site_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM site_aggregates + WHERE site_id = OLD.id; + END IF; + RETURN NULL; +END +$$; + diff --git a/migrations/2023-07-26-222023_site-aggregates-one/up.sql b/migrations/2023-07-26-222023_site-aggregates-one/up.sql index 7ed40316d..7d3c6c9b6 100644 --- a/migrations/2023-07-26-222023_site-aggregates-one/up.sql +++ b/migrations/2023-07-26-222023_site-aggregates-one/up.sql @@ -1,15 +1,32 @@ -create or replace function site_aggregates_site() -returns trigger language plpgsql -as $$ -begin - -- we only ever want to have a single value in site_aggregate because the site_aggregate triggers update all rows in that table. - -- a cleaner check would be to insert it for the local_site but that would break assumptions at least in the tests - IF (TG_OP = 'INSERT') AND NOT EXISTS (select id from site_aggregates limit 1) THEN - insert into site_aggregates (site_id) values (NEW.id); - ELSIF (TG_OP = 'DELETE') THEN - delete from site_aggregates where site_id = OLD.id; - END IF; - return null; -end $$; +CREATE OR REPLACE FUNCTION site_aggregates_site () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- we only ever want to have a single value in site_aggregate because the site_aggregate triggers update all rows in that table. + -- a cleaner check would be to insert it for the local_site but that would break assumptions at least in the tests + IF (TG_OP = 'INSERT') AND NOT EXISTS ( + SELECT + id + FROM + site_aggregates + LIMIT 1) THEN + INSERT INTO site_aggregates (site_id) + VALUES (NEW.id); + ELSIF (TG_OP = 'DELETE') THEN + DELETE FROM site_aggregates + WHERE site_id = OLD.id; + END IF; + RETURN NULL; +END +$$; + +DELETE FROM site_aggregates a +WHERE NOT EXISTS ( + SELECT + id + FROM + local_site s + WHERE + s.site_id = a.site_id); -delete from site_aggregates a where not exists (select id from local_site s where s.site_id = a.site_id); \ No newline at end of file diff --git a/migrations/2023-07-27-134652_remove-expensive-broken-trigger/down.sql b/migrations/2023-07-27-134652_remove-expensive-broken-trigger/down.sql index 1a5c4ec4f..3db25c4b0 100644 --- a/migrations/2023-07-27-134652_remove-expensive-broken-trigger/down.sql +++ b/migrations/2023-07-27-134652_remove-expensive-broken-trigger/down.sql @@ -1,80 +1,124 @@ -create or replace function person_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count + 1 where person_id = NEW.creator_id; - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count - 1 where person_id = OLD.creator_id; - +CREATE OR REPLACE FUNCTION person_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count - 1 + WHERE + person_id = OLD.creator_id; -- If the comment gets deleted, the score calculation trigger won't fire, -- so you need to re-calculate - update person_aggregates ua - set comment_score = cd.score - from ( - select u.id, - coalesce(0, sum(cl.score)) as score - -- User join because comments could be empty - from person u - left join comment c on u.id = c.creator_id and c.deleted = 'f' and c.removed = 'f' - left join comment_like cl on c.id = cl.comment_id - group by u.id - ) cd - where ua.person_id = OLD.creator_id; + UPDATE + person_aggregates ua + SET + comment_score = cd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(cl.score)) AS score + -- User join because comments could be empty + FROM + person u + LEFT JOIN comment c ON u.id = c.creator_id + AND c.deleted = 'f' + AND c.removed = 'f' + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY + u.id) cd + WHERE + ua.person_id = OLD.creator_id; END IF; - return null; -end $$; - -create or replace function person_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count + 1 where person_id = NEW.creator_id; - - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count - 1 where person_id = OLD.creator_id; + RETURN NULL; +END +$$; +CREATE OR REPLACE FUNCTION person_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count - 1 + WHERE + person_id = OLD.creator_id; -- If the post gets deleted, the score calculation trigger won't fire, -- so you need to re-calculate - update person_aggregates ua - set post_score = pd.score - from ( - select u.id, - coalesce(0, sum(pl.score)) as score - -- User join because posts could be empty - from person u - left join post p on u.id = p.creator_id and p.deleted = 'f' and p.removed = 'f' - left join post_like pl on p.id = pl.post_id - group by u.id - ) pd - where ua.person_id = OLD.creator_id; - + UPDATE + person_aggregates ua + SET + post_score = pd.score + FROM ( + SELECT + u.id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM + person u + LEFT JOIN post p ON u.id = p.creator_id + AND p.deleted = 'f' + AND p.removed = 'f' + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY + u.id) pd + WHERE + ua.person_id = OLD.creator_id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function community_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments + 1 from comment c, post p -where p.id = c.post_id - and p.id = NEW.post_id - and ca.community_id = p.community_id; -ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments - 1 from comment c, post p -where p.id = c.post_id - and p.id = OLD.post_id - and ca.community_id = p.community_id; +CREATE OR REPLACE FUNCTION community_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments + 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = NEW.post_id + AND ca.community_id = p.community_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments - 1 + FROM + comment c, + post p + WHERE + p.id = c.post_id + AND p.id = OLD.post_id + AND ca.community_id = p.community_id; + END IF; + RETURN NULL; +END +$$; -END IF; -return null; -end $$; \ No newline at end of file diff --git a/migrations/2023-07-27-134652_remove-expensive-broken-trigger/up.sql b/migrations/2023-07-27-134652_remove-expensive-broken-trigger/up.sql index 66a78371b..90385dd69 100644 --- a/migrations/2023-07-27-134652_remove-expensive-broken-trigger/up.sql +++ b/migrations/2023-07-27-134652_remove-expensive-broken-trigger/up.sql @@ -1,47 +1,78 @@ -create or replace function person_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count + 1 where person_id = NEW.creator_id; - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set comment_count = comment_count - 1 where person_id = OLD.creator_id; +CREATE OR REPLACE FUNCTION person_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + comment_count = comment_count - 1 + WHERE + person_id = OLD.creator_id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function person_aggregates_post_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count + 1 where person_id = NEW.creator_id; - - ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN - update person_aggregates - set post_count = post_count - 1 where person_id = OLD.creator_id; +CREATE OR REPLACE FUNCTION person_aggregates_post_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count + 1 + WHERE + person_id = NEW.creator_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + person_aggregates + SET + post_count = post_count - 1 + WHERE + person_id = OLD.creator_id; END IF; - return null; -end $$; + RETURN NULL; +END +$$; -create or replace function community_aggregates_comment_count() - returns trigger language plpgsql -as $$ -begin - IF (was_restored_or_created(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments + 1 from post p -where p.id = NEW.post_id - and ca.community_id = p.community_id; -ELSIF (was_removed_or_deleted(TG_OP, OLD, NEW)) THEN -update community_aggregates ca -set comments = comments - 1 from post p -where p.id = OLD.post_id - and ca.community_id = p.community_id; +CREATE OR REPLACE FUNCTION community_aggregates_comment_count () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + IF (was_restored_or_created (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments + 1 + FROM + post p + WHERE + p.id = NEW.post_id + AND ca.community_id = p.community_id; + ELSIF (was_removed_or_deleted (TG_OP, OLD, NEW)) THEN + UPDATE + community_aggregates ca + SET + comments = comments - 1 + FROM + post p + WHERE + p.id = OLD.post_id + AND ca.community_id = p.community_id; + END IF; + RETURN NULL; +END +$$; -END IF; -return null; -end $$; \ No newline at end of file diff --git a/scripts/fix-clippy.sh b/scripts/lint.sh similarity index 87% rename from scripts/fix-clippy.sh rename to scripts/lint.sh index 5ad3ca8b4..b06c5541f 100755 --- a/scripts/fix-clippy.sh +++ b/scripts/lint.sh @@ -21,5 +21,11 @@ cargo clippy --workspace --fix --allow-staged --allow-dirty --tests --all-target -D clippy::unwrap_used \ -D clippy::indexing_slicing +# Format rust files cargo +nightly fmt + +# Format toml files taplo format + +# Format sql files +find migrations -type f -name '*.sql' -exec pg_format -i {} + diff --git a/scripts/sql_format_check.sh b/scripts/sql_format_check.sh new file mode 100755 index 000000000..8a92eefd0 --- /dev/null +++ b/scripts/sql_format_check.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e + +# This check is only used for CI. + +CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" + +cd $CWD/../ + +find migrations -type f -name "*.sql" -print0 | while read -d $'\0' FILE +do + TMP_FILE="/tmp/tmp_pg_format.sql" + pg_format $FILE > $TMP_FILE + diff $FILE $TMP_FILE +done From 27be1efb74d6761046999980561a343d06235674 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 2 Aug 2023 18:52:41 +0200 Subject: [PATCH 10/11] Rewrite remaining federation actions, get rid of PerformCrud trait (#3794) * Rewrite ban actions * Rewrite delete/remove actions * Rewrite remove/delete community * Rewrite report actions * Rewrite feature/lock post * Rewrite update community actions * Rewrite remaining federation actions * Get rid of PerformCrud trait * clippy --- api_tests/prepare-drone-federation-test.sh | 3 - api_tests/run-federation-test.sh | 2 + crates/api/src/comment_report/create.rs | 97 +++--- crates/api/src/community/add_mod.rs | 111 +++---- crates/api/src/community/ban.rs | 143 +++++---- crates/api/src/community/block.rs | 93 +++--- crates/api/src/community/hide.rs | 59 ++-- crates/api/src/community/mod.rs | 10 +- crates/api/src/local_user/ban_person.rs | 114 +++---- crates/api/src/post/feature.rs | 113 ++++--- crates/api/src/post/like.rs | 16 +- crates/api/src/post/lock.rs | 97 +++--- crates/api/src/post_report/create.rs | 92 +++--- crates/api/src/post_report/mod.rs | 6 +- crates/api_common/src/build_response.rs | 14 +- crates/api_common/src/send_activity.rs | 36 ++- crates/api_crud/src/community/create.rs | 204 ++++++------ crates/api_crud/src/community/delete.rs | 62 ++-- crates/api_crud/src/community/remove.rs | 79 ++--- crates/api_crud/src/community/update.rs | 118 +++---- crates/api_crud/src/custom_emoji/create.rs | 65 ++-- crates/api_crud/src/custom_emoji/delete.rs | 36 +-- crates/api_crud/src/custom_emoji/mod.rs | 6 +- crates/api_crud/src/custom_emoji/update.rs | 63 ++-- crates/api_crud/src/lib.rs | 11 - crates/api_crud/src/post/create.rs | 4 +- crates/api_crud/src/post/delete.rs | 93 +++--- crates/api_crud/src/post/remove.rs | 97 +++--- crates/api_crud/src/post/update.rs | 16 +- crates/api_crud/src/private_message/create.rs | 132 ++++---- crates/api_crud/src/private_message/delete.rs | 76 ++--- crates/api_crud/src/private_message/update.rs | 88 +++--- crates/api_crud/src/user/create.rs | 293 +++++++++--------- crates/api_crud/src/user/delete.rs | 46 +-- crates/api_crud/src/user/mod.rs | 4 +- crates/apub/src/activities/block/mod.rs | 147 ++++----- .../activities/community/collection_add.rs | 92 +++--- .../src/activities/community/lock_page.rs | 96 +++--- .../apub/src/activities/community/report.rs | 65 +--- .../apub/src/activities/community/update.rs | 85 ++--- .../create_or_update/private_message.rs | 100 ++---- .../src/activities/deletion/delete_user.rs | 66 ++-- crates/apub/src/activities/deletion/mod.rs | 170 +++------- .../apub/src/activities/following/follow.rs | 32 +- crates/apub/src/activities/mod.rs | 91 +++++- src/api_routes_http.rs | 183 ++++------- 46 files changed, 1699 insertions(+), 1927 deletions(-) diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index 3aae16bda..ef1133287 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -30,9 +30,6 @@ else done fi -echo "killall existing lemmy_server processes" -killall -s1 lemmy_server || true - echo "$PWD" echo "start alpha" diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index f611cce65..ff74744a1 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -7,12 +7,14 @@ pushd .. cargo build rm target/lemmy_server || true cp target/debug/lemmy_server target/lemmy_server +killall -s1 lemmy_server || true ./api_tests/prepare-drone-federation-test.sh popd yarn yarn api-test || true +killall -s1 lemmy_server || true for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE" done diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs index 190e47a1e..2ea973d3c 100644 --- a/crates/api/src/comment_report/create.rs +++ b/crates/api/src/comment_report/create.rs @@ -1,8 +1,10 @@ -use crate::{check_report_reason, Perform}; -use actix_web::web::Data; +use crate::check_report_reason; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ comment::{CommentReportResponse, CreateCommentReport}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, local_user_view_from_jwt, @@ -21,55 +23,60 @@ use lemmy_db_views::structs::{CommentReportView, CommentView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Creates a comment report and notifies the moderators of the community -#[async_trait::async_trait(?Send)] -impl Perform for CreateCommentReport { - type Response = CommentReportResponse; +#[tracing::instrument(skip(context))] +pub async fn create_comment_report( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &CreateCommentReport = self; - 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(data.reason.trim()); + check_report_reason(&reason, &local_site)?; - let reason = sanitize_html(self.reason.trim()); - check_report_reason(&reason, &local_site)?; + let person_id = local_user_view.person.id; + let comment_id = data.comment_id; + let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; - let person_id = local_user_view.person.id; - let comment_id = data.comment_id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; + check_community_ban(person_id, comment_view.community.id, &mut context.pool()).await?; - check_community_ban(person_id, comment_view.community.id, &mut context.pool()).await?; + let report_form = CommentReportForm { + creator_id: person_id, + comment_id, + original_comment_text: comment_view.comment.content, + reason, + }; - let report_form = CommentReportForm { - creator_id: person_id, - comment_id, - original_comment_text: comment_view.comment.content, - reason, - }; + let report = CommentReport::report(&mut context.pool(), &report_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let report = CommentReport::report(&mut context.pool(), &report_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; + let comment_report_view = + CommentReportView::read(&mut context.pool(), report.id, person_id).await?; - let comment_report_view = - CommentReportView::read(&mut context.pool(), report.id, person_id).await?; - - // Email the admins - if local_site.reports_email_admins { - send_new_report_email_to_admins( - &comment_report_view.creator.name, - &comment_report_view.comment_creator.name, - &mut context.pool(), - context.settings(), - ) - .await?; - } - - Ok(CommentReportResponse { - comment_report_view, - }) + // Email the admins + if local_site.reports_email_admins { + send_new_report_email_to_admins( + &comment_report_view.creator.name, + &comment_report_view.comment_creator.name, + &mut context.pool(), + context.settings(), + ) + .await?; } + + ActivityChannel::submit_activity( + SendActivityData::CreateReport( + comment_view.comment.ap_id.inner().clone(), + local_user_view.person, + comment_view.community, + data.reason.clone(), + ), + &context, + ) + .await?; + + Ok(Json(CommentReportResponse { + comment_report_view, + })) } diff --git a/crates/api/src/community/add_mod.rs b/crates/api/src/community/add_mod.rs index 086207775..2d7b88750 100644 --- a/crates/api/src/community/add_mod.rs +++ b/crates/api/src/community/add_mod.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ community::{AddModToCommunity, AddModToCommunityResponse}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{is_mod_or_admin, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -15,58 +16,62 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for AddModToCommunity { - type Response = AddModToCommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn add_mod_to_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &AddModToCommunity = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let community_id = data.community_id; - let community_id = data.community_id; - - // Verify that only mods or admins can add mod - is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?; - let community = Community::read(&mut context.pool(), community_id).await?; - if local_user_view.person.admin && !community.local { - return Err(LemmyErrorType::NotAModerator)?; - } - - // Update in local database - let community_moderator_form = CommunityModeratorForm { - community_id: data.community_id, - person_id: data.person_id, - }; - if data.added { - CommunityModerator::join(&mut context.pool(), &community_moderator_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; - } else { - CommunityModerator::leave(&mut context.pool(), &community_moderator_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; - } - - // Mod tables - let form = ModAddCommunityForm { - mod_person_id: local_user_view.person.id, - other_person_id: data.person_id, - community_id: data.community_id, - removed: Some(!data.added), - }; - - ModAddCommunity::create(&mut context.pool(), &form).await?; - - // Note: in case a remote mod is added, this returns the old moderators list, it will only get - // updated once we receive an activity from the community (like `Announce/Add/Moderator`) - let community_id = data.community_id; - let moderators = - CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - - Ok(AddModToCommunityResponse { moderators }) + // Verify that only mods or admins can add mod + is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?; + let community = Community::read(&mut context.pool(), community_id).await?; + if local_user_view.person.admin && !community.local { + return Err(LemmyErrorType::NotAModerator)?; } + + // Update in local database + let community_moderator_form = CommunityModeratorForm { + community_id: data.community_id, + person_id: data.person_id, + }; + if data.added { + CommunityModerator::join(&mut context.pool(), &community_moderator_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; + } else { + CommunityModerator::leave(&mut context.pool(), &community_moderator_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; + } + + // Mod tables + let form = ModAddCommunityForm { + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, + community_id: data.community_id, + removed: Some(!data.added), + }; + + ModAddCommunity::create(&mut context.pool(), &form).await?; + + // Note: in case a remote mod is added, this returns the old moderators list, it will only get + // updated once we receive an activity from the community (like `Announce/Add/Moderator`) + let community_id = data.community_id; + let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; + + ActivityChannel::submit_activity( + SendActivityData::AddModToCommunity( + local_user_view.person, + data.community_id, + data.person_id, + data.added, + ), + &context, + ) + .await?; + + Ok(Json(AddModToCommunityResponse { moderators })) } diff --git a/crates/api/src/community/ban.rs b/crates/api/src/community/ban.rs index 95c2bbc04..d04a8a0a9 100644 --- a/crates/api/src/community/ban.rs +++ b/crates/api/src/community/ban.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ community::{BanFromCommunity, BanFromCommunityResponse}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{ is_mod_or_admin, local_user_view_from_jwt, @@ -28,77 +29,85 @@ use lemmy_utils::{ utils::{time::naive_from_unix, validation::is_valid_body_field}, }; -#[async_trait::async_trait(?Send)] -impl Perform for BanFromCommunity { - type Response = BanFromCommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn ban_from_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &BanFromCommunity = self; - 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); - let community_id = data.community_id; - let banned_person_id = data.person_id; - let remove_data = data.remove_data.unwrap_or(false); - let expires = data.expires.map(naive_from_unix); + // Verify that only mods or admins can ban + is_mod_or_admin( + &mut context.pool(), + local_user_view.person.id, + data.community_id, + ) + .await?; + is_valid_body_field(&data.reason, false)?; - // Verify that only mods or admins can ban - is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?; - is_valid_body_field(&data.reason, false)?; + let community_user_ban_form = CommunityPersonBanForm { + community_id: data.community_id, + person_id: data.person_id, + expires: Some(expires), + }; - let community_user_ban_form = CommunityPersonBanForm { + if data.ban { + CommunityPersonBan::ban(&mut context.pool(), &community_user_ban_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?; + + // Also unsubscribe them from the community, if they are subscribed + let community_follower_form = CommunityFollowerForm { community_id: data.community_id, - person_id: data.person_id, - expires: Some(expires), + person_id: banned_person_id, + pending: false, }; - if data.ban { - CommunityPersonBan::ban(&mut context.pool(), &community_user_ban_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?; - - // Also unsubscribe them from the community, if they are subscribed - let community_follower_form = CommunityFollowerForm { - community_id: data.community_id, - person_id: banned_person_id, - pending: false, - }; - - CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) - .await - .ok(); - } else { - CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?; - } - - // Remove/Restore their data if that's desired - if remove_data { - remove_user_data_in_community(community_id, banned_person_id, &mut context.pool()).await?; - } - - // Mod tables - let form = ModBanFromCommunityForm { - mod_person_id: local_user_view.person.id, - other_person_id: data.person_id, - community_id: data.community_id, - reason: sanitize_html_opt(&data.reason), - banned: Some(data.ban), - expires, - }; - - ModBanFromCommunity::create(&mut context.pool(), &form).await?; - - let person_id = data.person_id; - let person_view = PersonView::read(&mut context.pool(), person_id).await?; - - Ok(BanFromCommunityResponse { - person_view, - banned: data.ban, - }) + CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + .await + .ok(); + } else { + CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?; } + + // Remove/Restore their data if that's desired + if remove_data { + remove_user_data_in_community(data.community_id, banned_person_id, &mut context.pool()).await?; + } + + // Mod tables + let form = ModBanFromCommunityForm { + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, + community_id: data.community_id, + reason: sanitize_html_opt(&data.reason), + banned: Some(data.ban), + expires, + }; + + ModBanFromCommunity::create(&mut context.pool(), &form).await?; + + let person_view = PersonView::read(&mut context.pool(), data.person_id).await?; + + ActivityChannel::submit_activity( + SendActivityData::BanFromCommunity( + local_user_view.person, + data.community_id, + person_view.person.clone(), + data.0.clone(), + ), + &context, + ) + .await?; + + Ok(Json(BanFromCommunityResponse { + person_view, + banned: data.ban, + })) } diff --git a/crates/api/src/community/block.rs b/crates/api/src/community/block.rs index 66d6adac6..f807574ed 100644 --- a/crates/api/src/community/block.rs +++ b/crates/api/src/community/block.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ community::{BlockCommunity, BlockCommunityResponse}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ @@ -15,52 +16,56 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for BlockCommunity { - type Response = BlockCommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn block_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &BlockCommunity = self; - 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 { + person_id, + community_id, + }; - let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_block_form = CommunityBlockForm { + if data.block { + CommunityBlock::block(&mut context.pool(), &community_block_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?; + + // Also, unfollow the community, and send a federated unfollow + let community_follower_form = CommunityFollowerForm { + community_id: data.community_id, person_id, - community_id, + pending: false, }; - if data.block { - CommunityBlock::block(&mut context.pool(), &community_block_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?; - - // Also, unfollow the community, and send a federated unfollow - let community_follower_form = CommunityFollowerForm { - community_id: data.community_id, - person_id, - pending: false, - }; - - CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) - .await - .ok(); - } else { - CommunityBlock::unblock(&mut context.pool(), &community_block_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?; - } - - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; - - Ok(BlockCommunityResponse { - blocked: data.block, - community_view, - }) + CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + .await + .ok(); + } else { + CommunityBlock::unblock(&mut context.pool(), &community_block_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?; } + + let community_view = + CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; + + ActivityChannel::submit_activity( + SendActivityData::FollowCommunity( + community_view.community.clone(), + local_user_view.person.clone(), + false, + ), + &context, + ) + .await?; + + Ok(Json(BlockCommunityResponse { + blocked: data.block, + community_view, + })) } diff --git a/crates/api/src/community/hide.rs b/crates/api/src/community/hide.rs index 4c05a71cf..ce437ad99 100644 --- a/crates/api/src/community/hide.rs +++ b/crates/api/src/community/hide.rs @@ -1,9 +1,10 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_community_response, community::{CommunityResponse, HideCommunity}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{is_admin, local_user_view_from_jwt, sanitize_html_opt}, }; use lemmy_db_schema::{ @@ -15,36 +16,38 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for HideCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn hide_community( + data: Json, + context: Data, +) -> 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)?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &HideCommunity = self; + let community_form = CommunityUpdateForm::builder() + .hidden(Some(data.hidden)) + .build(); - // 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 mod_hide_community_form = ModHideCommunityForm { + community_id: data.community_id, + mod_person_id: local_user_view.person.id, + reason: sanitize_html_opt(&data.reason), + hidden: Some(data.hidden), + }; - let community_form = CommunityUpdateForm::builder() - .hidden(Some(data.hidden)) - .build(); + let community_id = data.community_id; + let community = Community::update(&mut context.pool(), community_id, &community_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunityHiddenStatus)?; - let mod_hide_community_form = ModHideCommunityForm { - community_id: data.community_id, - mod_person_id: local_user_view.person.id, - reason: sanitize_html_opt(&data.reason), - hidden: Some(data.hidden), - }; + ModHideCommunity::create(&mut context.pool(), &mod_hide_community_form).await?; - let community_id = data.community_id; - Community::update(&mut context.pool(), community_id, &community_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunityHiddenStatus)?; + ActivityChannel::submit_activity( + SendActivityData::UpdateCommunity(local_user_view.person.clone(), community), + &context, + ) + .await?; - ModHideCommunity::create(&mut context.pool(), &mod_hide_community_form).await?; - - build_community_response(context, local_user_view, community_id).await - } + build_community_response(&context, local_user_view, community_id).await } diff --git a/crates/api/src/community/mod.rs b/crates/api/src/community/mod.rs index fc3ef67c5..478192229 100644 --- a/crates/api/src/community/mod.rs +++ b/crates/api/src/community/mod.rs @@ -1,6 +1,6 @@ -mod add_mod; -mod ban; -mod block; +pub mod add_mod; +pub mod ban; +pub mod block; pub mod follow; -mod hide; -mod transfer; +pub mod hide; +pub mod transfer; diff --git a/crates/api/src/local_user/ban_person.rs b/crates/api/src/local_user/ban_person.rs index 77e8e8056..6e99ef250 100644 --- a/crates/api/src/local_user/ban_person.rs +++ b/crates/api/src/local_user/ban_person.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; 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_opt}, }; use lemmy_db_schema::{ @@ -17,65 +18,68 @@ use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, utils::{time::naive_from_unix, validation::is_valid_body_field}, }; +#[tracing::instrument(skip(context))] +pub async fn ban_from_site( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; -#[async_trait::async_trait(?Send)] -impl Perform for BanPerson { - type Response = BanPersonResponse; + // Make sure user is an admin + is_admin(&local_user_view)?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &BanPerson = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + is_valid_body_field(&data.reason, false)?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let expires = data.expires.map(naive_from_unix); - is_valid_body_field(&data.reason, false)?; + let person = Person::update( + &mut context.pool(), + data.person_id, + &PersonUpdateForm::builder() + .banned(Some(data.ban)) + .ban_expires(Some(expires)) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; - let ban = data.ban; - let banned_person_id = data.person_id; - let expires = data.expires.map(naive_from_unix); - - let person = Person::update( + // Remove their data if that's desired + let remove_data = data.remove_data.unwrap_or(false); + if remove_data { + remove_user_data( + person.id, &mut context.pool(), - banned_person_id, - &PersonUpdateForm::builder() - .banned(Some(ban)) - .ban_expires(Some(expires)) - .build(), + context.settings(), + context.client(), ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; - - // Remove their data if that's desired - let remove_data = data.remove_data.unwrap_or(false); - if remove_data { - remove_user_data( - person.id, - &mut context.pool(), - context.settings(), - context.client(), - ) - .await?; - } - - // Mod tables - let form = ModBanForm { - mod_person_id: local_user_view.person.id, - other_person_id: data.person_id, - reason: sanitize_html_opt(&data.reason), - banned: Some(data.ban), - expires, - }; - - ModBan::create(&mut context.pool(), &form).await?; - - let person_id = data.person_id; - let person_view = PersonView::read(&mut context.pool(), person_id).await?; - - Ok(BanPersonResponse { - person_view, - banned: data.ban, - }) + .await?; } + + // Mod tables + let form = ModBanForm { + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, + reason: sanitize_html_opt(&data.reason), + banned: Some(data.ban), + expires, + }; + + ModBan::create(&mut context.pool(), &form).await?; + + let person_view = PersonView::read(&mut context.pool(), data.person_id).await?; + + ActivityChannel::submit_activity( + SendActivityData::BanFromSite( + local_user_view.person, + person_view.person.clone(), + data.0.clone(), + ), + &context, + ) + .await?; + + Ok(Json(BanPersonResponse { + person_view, + banned: data.ban, + })) } diff --git a/crates/api/src/post/feature.rs b/crates/api/src/post/feature.rs index c59eba313..5e18c2b64 100644 --- a/crates/api/src/post/feature.rs +++ b/crates/api/src/post/feature.rs @@ -1,9 +1,10 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{FeaturePost, PostResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, check_community_deleted_or_removed, @@ -22,67 +23,65 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for FeaturePost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn feature_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &FeaturePost = self; - 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?; - let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + check_community_ban( + local_user_view.person.id, + orig_post.community_id, + &mut context.pool(), + ) + .await?; + check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; - check_community_ban( + if data.feature_type == PostFeatureType::Community { + // Verify that only the mods can feature in community + is_mod_or_admin( + &mut context.pool(), local_user_view.person.id, orig_post.community_id, - &mut context.pool(), ) .await?; - check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; - - if data.feature_type == PostFeatureType::Community { - // Verify that only the mods can feature in community - is_mod_or_admin( - &mut context.pool(), - local_user_view.person.id, - orig_post.community_id, - ) - .await?; - } else { - is_admin(&local_user_view)?; - } - - // Update the post - let post_id = data.post_id; - let new_post: PostUpdateForm = if data.feature_type == PostFeatureType::Community { - PostUpdateForm::builder() - .featured_community(Some(data.featured)) - .build() - } else { - PostUpdateForm::builder() - .featured_local(Some(data.featured)) - .build() - }; - Post::update(&mut context.pool(), post_id, &new_post).await?; - - // Mod tables - let form = ModFeaturePostForm { - mod_person_id: local_user_view.person.id, - post_id: data.post_id, - featured: data.featured, - is_featured_community: data.feature_type == PostFeatureType::Community, - }; - - ModFeaturePost::create(&mut context.pool(), &form).await?; - - build_post_response( - context, - orig_post.community_id, - local_user_view.person.id, - post_id, - ) - .await + } else { + is_admin(&local_user_view)?; } + + // Update the post + let post_id = data.post_id; + let new_post: PostUpdateForm = if data.feature_type == PostFeatureType::Community { + PostUpdateForm::builder() + .featured_community(Some(data.featured)) + .build() + } else { + PostUpdateForm::builder() + .featured_local(Some(data.featured)) + .build() + }; + let post = Post::update(&mut context.pool(), post_id, &new_post).await?; + + // Mod tables + let form = ModFeaturePostForm { + mod_person_id: local_user_view.person.id, + post_id: data.post_id, + featured: data.featured, + is_featured_community: data.feature_type == PostFeatureType::Community, + }; + + ModFeaturePost::create(&mut context.pool(), &form).await?; + + let person_id = local_user_view.person.id; + ActivityChannel::submit_activity( + SendActivityData::FeaturePost(post, local_user_view.person, data.featured), + &context, + ) + .await?; + + build_post_response(&context, orig_post.community_id, person_id, post_id).await } diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index 1ff119f03..b9b2bede0 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -80,13 +80,11 @@ pub async fn like_post( ) .await?; - Ok(Json( - build_post_response( - context.deref(), - post.community_id, - local_user_view.person.id, - post_id, - ) - .await?, - )) + build_post_response( + context.deref(), + post.community_id, + local_user_view.person.id, + post_id, + ) + .await } diff --git a/crates/api/src/post/lock.rs b/crates/api/src/post/lock.rs index 627e9d8eb..45ec3317f 100644 --- a/crates/api/src/post/lock.rs +++ b/crates/api/src/post/lock.rs @@ -1,9 +1,10 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{LockPost, PostResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, check_community_deleted_or_removed, @@ -20,58 +21,56 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for LockPost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn lock_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &LockPost = self; - 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?; - let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + check_community_ban( + local_user_view.person.id, + orig_post.community_id, + &mut context.pool(), + ) + .await?; + check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; - check_community_ban( - local_user_view.person.id, - orig_post.community_id, - &mut context.pool(), - ) - .await?; - check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; + // Verify that only the mods can lock + is_mod_or_admin( + &mut context.pool(), + local_user_view.person.id, + orig_post.community_id, + ) + .await?; - // Verify that only the mods can lock - is_mod_or_admin( - &mut context.pool(), - local_user_view.person.id, - orig_post.community_id, - ) - .await?; + // Update the post + let post_id = data.post_id; + let locked = data.locked; + let post = Post::update( + &mut context.pool(), + post_id, + &PostUpdateForm::builder().locked(Some(locked)).build(), + ) + .await?; - // Update the post - let post_id = data.post_id; - let locked = data.locked; - Post::update( - &mut context.pool(), - post_id, - &PostUpdateForm::builder().locked(Some(locked)).build(), - ) - .await?; + // Mod tables + let form = ModLockPostForm { + mod_person_id: local_user_view.person.id, + post_id: data.post_id, + locked: Some(locked), + }; + ModLockPost::create(&mut context.pool(), &form).await?; - // Mod tables - let form = ModLockPostForm { - mod_person_id: local_user_view.person.id, - post_id: data.post_id, - locked: Some(locked), - }; - ModLockPost::create(&mut context.pool(), &form).await?; + let person_id = local_user_view.person.id; + ActivityChannel::submit_activity( + SendActivityData::LockPost(post, local_user_view.person, data.locked), + &context, + ) + .await?; - build_post_response( - context, - orig_post.community_id, - local_user_view.person.id, - post_id, - ) - .await - } + build_post_response(&context, orig_post.community_id, person_id, post_id).await } diff --git a/crates/api/src/post_report/create.rs b/crates/api/src/post_report/create.rs index a4081015c..68eb8f7bd 100644 --- a/crates/api/src/post_report/create.rs +++ b/crates/api/src/post_report/create.rs @@ -1,8 +1,10 @@ -use crate::{check_report_reason, Perform}; -use actix_web::web::Data; +use crate::check_report_reason; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, post::{CreatePostReport, PostReportResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, local_user_view_from_jwt, @@ -21,51 +23,59 @@ use lemmy_db_views::structs::{PostReportView, PostView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Creates a post report and notifies the moderators of the community -#[async_trait::async_trait(?Send)] -impl Perform for CreatePostReport { - type Response = PostReportResponse; +#[tracing::instrument(skip(context))] +pub async fn create_post_report( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreatePostReport = self; - 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(data.reason.trim()); + check_report_reason(&reason, &local_site)?; - let reason = sanitize_html(self.reason.trim()); - check_report_reason(&reason, &local_site)?; + let person_id = local_user_view.person.id; + let post_id = data.post_id; + let post_view = PostView::read(&mut context.pool(), post_id, None, None).await?; - let person_id = local_user_view.person.id; - let post_id = data.post_id; - let post_view = PostView::read(&mut context.pool(), post_id, None, None).await?; + check_community_ban(person_id, post_view.community.id, &mut context.pool()).await?; - check_community_ban(person_id, post_view.community.id, &mut context.pool()).await?; + let report_form = PostReportForm { + creator_id: person_id, + post_id, + original_post_name: post_view.post.name, + original_post_url: post_view.post.url, + original_post_body: post_view.post.body, + reason, + }; - let report_form = PostReportForm { - creator_id: person_id, - post_id, - original_post_name: post_view.post.name, - original_post_url: post_view.post.url, - original_post_body: post_view.post.body, - reason, - }; + let report = PostReport::report(&mut context.pool(), &report_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let report = PostReport::report(&mut context.pool(), &report_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; + let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id).await?; - let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id).await?; - - // Email the admins - if local_site.reports_email_admins { - send_new_report_email_to_admins( - &post_report_view.creator.name, - &post_report_view.post_creator.name, - &mut context.pool(), - context.settings(), - ) - .await?; - } - - Ok(PostReportResponse { post_report_view }) + // Email the admins + if local_site.reports_email_admins { + send_new_report_email_to_admins( + &post_report_view.creator.name, + &post_report_view.post_creator.name, + &mut context.pool(), + context.settings(), + ) + .await?; } + + ActivityChannel::submit_activity( + SendActivityData::CreateReport( + post_view.post.ap_id.inner().clone(), + local_user_view.person, + post_view.community, + data.reason.clone(), + ), + &context, + ) + .await?; + + Ok(Json(PostReportResponse { post_report_view })) } diff --git a/crates/api/src/post_report/mod.rs b/crates/api/src/post_report/mod.rs index 375fde4c3..3bb1a9b46 100644 --- a/crates/api/src/post_report/mod.rs +++ b/crates/api/src/post_report/mod.rs @@ -1,3 +1,3 @@ -mod create; -mod list; -mod resolve; +pub mod create; +pub mod list; +pub mod resolve; diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index b8c02457d..8d3bcda1a 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -5,7 +5,7 @@ use crate::{ post::PostResponse, utils::{check_person_block, get_interface_language, is_mod_or_admin, send_email_to_user}, }; -use actix_web::web::Data; +use actix_web::web::Json; use lemmy_db_schema::{ newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId}, source::{ @@ -39,10 +39,10 @@ pub async fn build_comment_response( } pub async fn build_community_response( - context: &Data, + context: &LemmyContext, local_user_view: LocalUserView, community_id: CommunityId, -) -> Result { +) -> Result, LemmyError> { let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id) .await @@ -57,10 +57,10 @@ pub async fn build_community_response( .await?; let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; - Ok(CommunityResponse { + Ok(Json(CommunityResponse { community_view, discussion_languages, - }) + })) } pub async fn build_post_response( @@ -68,7 +68,7 @@ pub async fn build_post_response( community_id: CommunityId, person_id: PersonId, post_id: PostId, -) -> Result { +) -> Result, LemmyError> { let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), person_id, community_id) .await .is_ok(); @@ -79,7 +79,7 @@ pub async fn build_post_response( Some(is_mod_or_admin), ) .await?; - Ok(PostResponse { post_view }) + Ok(Json(PostResponse { post_view })) } // TODO: this function is a mess and should be split up to handle email seperately diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 8580c2175..1ba9aa646 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -1,10 +1,22 @@ -use crate::context::LemmyContext; +use crate::{ + community::BanFromCommunity, + context::LemmyContext, + person::BanPerson, + post::{DeletePost, RemovePost}, +}; use activitypub_federation::config::Data; use futures::future::BoxFuture; use lemmy_db_schema::{ - newtypes::DbUrl, - source::{comment::Comment, community::Community, person::Person, post::Post}, + newtypes::{CommunityId, DbUrl, PersonId}, + source::{ + comment::Comment, + community::Community, + person::Person, + post::Post, + private_message::PrivateMessage, + }, }; +use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::{error::LemmyResult, SYNCHRONOUS_FEDERATION}; use once_cell::sync::{Lazy, OnceCell}; use tokio::{ @@ -15,6 +27,7 @@ use tokio::{ }, task::JoinHandle, }; +use url::Url; type MatchOutgoingActivitiesBoxed = Box fn(SendActivityData, &'a Data) -> BoxFuture<'a, LemmyResult<()>>>; @@ -26,12 +39,27 @@ pub static MATCH_OUTGOING_ACTIVITIES: OnceCell = O pub enum SendActivityData { CreatePost(Post), UpdatePost(Post), + DeletePost(Post, Person, DeletePost), + RemovePost(Post, Person, RemovePost), + LockPost(Post, Person, bool), + FeaturePost(Post, Person, bool), CreateComment(Comment), + UpdateComment(Comment), DeleteComment(Comment, Person, Community), RemoveComment(Comment, Person, Community, Option), - UpdateComment(Comment), LikePostOrComment(DbUrl, Person, Community, i16), FollowCommunity(Community, Person, bool), + UpdateCommunity(Person, Community), + DeleteCommunity(Person, Community, bool), + RemoveCommunity(Person, Community, Option, bool), + AddModToCommunity(Person, CommunityId, PersonId, bool), + BanFromCommunity(Person, CommunityId, Person, BanFromCommunity), + BanFromSite(Person, Person, BanPerson), + CreatePrivateMessage(PrivateMessageView), + UpdatePrivateMessage(PrivateMessageView), + DeletePrivateMessage(Person, PrivateMessage, bool), + DeleteUser(Person), + CreateReport(Url, Person, Community, String), } // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 7c84a2150..7bfeabd6d 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -1,6 +1,5 @@ -use crate::PerformCrud; -use activitypub_federation::http_signatures::generate_actor_keypair; -use actix_web::web::Data; +use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair}; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_community_response, community::{CommunityResponse, CreateCommunity}, @@ -42,107 +41,104 @@ use lemmy_utils::{ }, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for CreateCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn create_community( + data: Json, + context: Data, +) -> 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; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreateCommunity = self; - 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; - - if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() { - return Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?; - } - - // Check to make sure the icon and banners are urls - let icon = diesel_option_overwrite_to_url_create(&data.icon)?; - let banner = diesel_option_overwrite_to_url_create(&data.banner)?; - - let name = sanitize_html(&data.name); - let title = sanitize_html(&data.title); - let description = sanitize_html_opt(&data.description); - - let slur_regex = local_site_to_slur_regex(&local_site); - check_slurs(&name, &slur_regex)?; - check_slurs(&title, &slur_regex)?; - check_slurs_opt(&description, &slur_regex)?; - - is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?; - is_valid_body_field(&data.description, false)?; - - // Double check for duplicate community actor_ids - let community_actor_id = generate_local_apub_endpoint( - EndpointType::Community, - &data.name, - &context.settings().get_protocol_and_hostname(), - )?; - let community_dupe = - Community::read_from_apub_id(&mut context.pool(), &community_actor_id).await?; - if community_dupe.is_some() { - return Err(LemmyErrorType::CommunityAlreadyExists)?; - } - - // When you create a community, make sure the user becomes a moderator and a follower - let keypair = generate_actor_keypair()?; - - let community_form = CommunityInsertForm::builder() - .name(name) - .title(title) - .description(description) - .icon(icon) - .banner(banner) - .nsfw(data.nsfw) - .actor_id(Some(community_actor_id.clone())) - .private_key(Some(keypair.private_key)) - .public_key(keypair.public_key) - .followers_url(Some(generate_followers_url(&community_actor_id)?)) - .inbox_url(Some(generate_inbox_url(&community_actor_id)?)) - .shared_inbox_url(Some(generate_shared_inbox_url(&community_actor_id)?)) - .posting_restricted_to_mods(data.posting_restricted_to_mods) - .instance_id(site_view.site.instance_id) - .build(); - - let inserted_community = Community::create(&mut context.pool(), &community_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityAlreadyExists)?; - - // The community creator becomes a moderator - let community_moderator_form = CommunityModeratorForm { - community_id: inserted_community.id, - person_id: local_user_view.person.id, - }; - - CommunityModerator::join(&mut context.pool(), &community_moderator_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; - - // Follow your own community - let community_follower_form = CommunityFollowerForm { - community_id: inserted_community.id, - person_id: local_user_view.person.id, - pending: false, - }; - - CommunityFollower::follow(&mut context.pool(), &community_follower_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; - - // Update the discussion_languages if that's provided - let community_id = inserted_community.id; - if let Some(languages) = data.discussion_languages.clone() { - let site_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; - // check that community languages are a subset of site languages - // https://stackoverflow.com/a/64227550 - let is_subset = languages.iter().all(|item| site_languages.contains(item)); - if !is_subset { - return Err(LemmyErrorType::LanguageNotAllowed)?; - } - CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; - } - - build_community_response(context, local_user_view, community_id).await + if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() { + return Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?; } + + // Check to make sure the icon and banners are urls + let icon = diesel_option_overwrite_to_url_create(&data.icon)?; + let banner = diesel_option_overwrite_to_url_create(&data.banner)?; + + let name = sanitize_html(&data.name); + let title = sanitize_html(&data.title); + let description = sanitize_html_opt(&data.description); + + let slur_regex = local_site_to_slur_regex(&local_site); + check_slurs(&name, &slur_regex)?; + check_slurs(&title, &slur_regex)?; + check_slurs_opt(&description, &slur_regex)?; + + is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?; + is_valid_body_field(&data.description, false)?; + + // Double check for duplicate community actor_ids + let community_actor_id = generate_local_apub_endpoint( + EndpointType::Community, + &data.name, + &context.settings().get_protocol_and_hostname(), + )?; + let community_dupe = + Community::read_from_apub_id(&mut context.pool(), &community_actor_id).await?; + if community_dupe.is_some() { + return Err(LemmyErrorType::CommunityAlreadyExists)?; + } + + // When you create a community, make sure the user becomes a moderator and a follower + let keypair = generate_actor_keypair()?; + + let community_form = CommunityInsertForm::builder() + .name(name) + .title(title) + .description(description) + .icon(icon) + .banner(banner) + .nsfw(data.nsfw) + .actor_id(Some(community_actor_id.clone())) + .private_key(Some(keypair.private_key)) + .public_key(keypair.public_key) + .followers_url(Some(generate_followers_url(&community_actor_id)?)) + .inbox_url(Some(generate_inbox_url(&community_actor_id)?)) + .shared_inbox_url(Some(generate_shared_inbox_url(&community_actor_id)?)) + .posting_restricted_to_mods(data.posting_restricted_to_mods) + .instance_id(site_view.site.instance_id) + .build(); + + let inserted_community = Community::create(&mut context.pool(), &community_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityAlreadyExists)?; + + // The community creator becomes a moderator + let community_moderator_form = CommunityModeratorForm { + community_id: inserted_community.id, + person_id: local_user_view.person.id, + }; + + CommunityModerator::join(&mut context.pool(), &community_moderator_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; + + // Follow your own community + let community_follower_form = CommunityFollowerForm { + community_id: inserted_community.id, + person_id: local_user_view.person.id, + pending: false, + }; + + CommunityFollower::follow(&mut context.pool(), &community_follower_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; + + // Update the discussion_languages if that's provided + let community_id = inserted_community.id; + if let Some(languages) = data.discussion_languages.clone() { + let site_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; + // check that community languages are a subset of site languages + // https://stackoverflow.com/a/64227550 + let is_subset = languages.iter().all(|item| site_languages.contains(item)); + if !is_subset { + return Err(LemmyErrorType::LanguageNotAllowed)?; + } + CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; + } + + build_community_response(&context, local_user_view, community_id).await } diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index d3e58d56c..e23b1f404 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_community_response, community::{CommunityResponse, DeleteCommunity}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{is_top_mod, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -13,36 +14,39 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeleteCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &DeleteCommunity = self; - 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 = + CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - // Fetch the community mods - let community_id = data.community_id; - let community_mods = - CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; + // Make sure deleter is the top mod + is_top_mod(&local_user_view, &community_mods)?; - // Make sure deleter is the top mod - is_top_mod(&local_user_view, &community_mods)?; + // Do the delete + let community_id = data.community_id; + let deleted = data.deleted; + let community = Community::update( + &mut context.pool(), + community_id, + &CommunityUpdateForm::builder() + .deleted(Some(deleted)) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; - // Do the delete - let community_id = data.community_id; - let deleted = data.deleted; - Community::update( - &mut context.pool(), - community_id, - &CommunityUpdateForm::builder() - .deleted(Some(deleted)) - .build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; + ActivityChannel::submit_activity( + SendActivityData::DeleteCommunity(local_user_view.person.clone(), community, data.deleted), + &context, + ) + .await?; - build_community_response(context, local_user_view, community_id).await - } + build_community_response(&context, local_user_view, community_id).await } diff --git a/crates/api_crud/src/community/remove.rs b/crates/api_crud/src/community/remove.rs index 2bcd3d857..b79b2a666 100644 --- a/crates/api_crud/src/community/remove.rs +++ b/crates/api_crud/src/community/remove.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_community_response, community::{CommunityResponse, RemoveCommunity}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{is_admin, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -18,42 +19,50 @@ use lemmy_utils::{ utils::time::naive_from_unix, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for RemoveCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn remove_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &RemoveCommunity = self; - 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)?; - // Verify its an admin (only an admin can remove a community) - is_admin(&local_user_view)?; + // Do the remove + let community_id = data.community_id; + let removed = data.removed; + let community = Community::update( + &mut context.pool(), + community_id, + &CommunityUpdateForm::builder() + .removed(Some(removed)) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; - // Do the remove - let community_id = data.community_id; - let removed = data.removed; - Community::update( - &mut context.pool(), - community_id, - &CommunityUpdateForm::builder() - .removed(Some(removed)) - .build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; + // Mod tables + let expires = data.expires.map(naive_from_unix); + let form = ModRemoveCommunityForm { + mod_person_id: local_user_view.person.id, + community_id: data.community_id, + removed: Some(removed), + reason: data.reason.clone(), + expires, + }; + ModRemoveCommunity::create(&mut context.pool(), &form).await?; - // Mod tables - let expires = data.expires.map(naive_from_unix); - let form = ModRemoveCommunityForm { - mod_person_id: local_user_view.person.id, - community_id: data.community_id, - removed: Some(removed), - reason: data.reason.clone(), - expires, - }; - ModRemoveCommunity::create(&mut context.pool(), &form).await?; + ActivityChannel::submit_activity( + SendActivityData::RemoveCommunity( + local_user_view.person.clone(), + community, + data.reason.clone(), + data.removed, + ), + &context, + ) + .await?; - build_community_response(context, local_user_view, community_id).await - } + build_community_response(&context, local_user_view, community_id).await } diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index 128be036f..baa4e1bdb 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_community_response, community::{CommunityResponse, EditCommunity}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{local_site_to_slur_regex, local_user_view_from_jwt, sanitize_html_opt}, }; use lemmy_db_schema::{ @@ -22,65 +23,68 @@ use lemmy_utils::{ utils::{slurs::check_slurs_opt, validation::is_valid_body_field}, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn update_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &EditCommunity = self; - 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); + check_slurs_opt(&data.title, &slur_regex)?; + check_slurs_opt(&data.description, &slur_regex)?; + is_valid_body_field(&data.description, false)?; - let slur_regex = local_site_to_slur_regex(&local_site); - check_slurs_opt(&data.title, &slur_regex)?; - check_slurs_opt(&data.description, &slur_regex)?; - is_valid_body_field(&data.description, false)?; + let title = sanitize_html_opt(&data.title); + let description = sanitize_html_opt(&data.description); - let title = sanitize_html_opt(&data.title); - let description = sanitize_html_opt(&data.description); + let icon = diesel_option_overwrite_to_url(&data.icon)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; + let description = diesel_option_overwrite(description); - let icon = diesel_option_overwrite_to_url(&data.icon)?; - let banner = diesel_option_overwrite_to_url(&data.banner)?; - let description = diesel_option_overwrite(description); - - // Verify its a mod (only mods can edit it) - let community_id = data.community_id; - let mods: Vec = - CommunityModeratorView::for_community(&mut context.pool(), community_id) - .await - .map(|v| v.into_iter().map(|m| m.moderator.id).collect())?; - if !mods.contains(&local_user_view.person.id) { - return Err(LemmyErrorType::NotAModerator)?; - } - - let community_id = data.community_id; - if let Some(languages) = data.discussion_languages.clone() { - let site_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; - // check that community languages are a subset of site languages - // https://stackoverflow.com/a/64227550 - let is_subset = languages.iter().all(|item| site_languages.contains(item)); - if !is_subset { - return Err(LemmyErrorType::LanguageNotAllowed)?; - } - CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; - } - - let community_form = CommunityUpdateForm::builder() - .title(title) - .description(description) - .icon(icon) - .banner(banner) - .nsfw(data.nsfw) - .posting_restricted_to_mods(data.posting_restricted_to_mods) - .updated(Some(Some(naive_now()))) - .build(); - - let community_id = data.community_id; - Community::update(&mut context.pool(), community_id, &community_form) + // Verify its a mod (only mods can edit it) + let community_id = data.community_id; + let mods: Vec = + CommunityModeratorView::for_community(&mut context.pool(), community_id) .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; - - build_community_response(context, local_user_view, community_id).await + .map(|v| v.into_iter().map(|m| m.moderator.id).collect())?; + if !mods.contains(&local_user_view.person.id) { + return Err(LemmyErrorType::NotAModerator)?; } + + let community_id = data.community_id; + if let Some(languages) = data.discussion_languages.clone() { + let site_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; + // check that community languages are a subset of site languages + // https://stackoverflow.com/a/64227550 + let is_subset = languages.iter().all(|item| site_languages.contains(item)); + if !is_subset { + return Err(LemmyErrorType::LanguageNotAllowed)?; + } + CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; + } + + let community_form = CommunityUpdateForm::builder() + .title(title) + .description(description) + .icon(icon) + .banner(banner) + .nsfw(data.nsfw) + .posting_restricted_to_mods(data.posting_restricted_to_mods) + .updated(Some(Some(naive_now()))) + .build(); + + let community_id = data.community_id; + let community = Community::update(&mut context.pool(), community_id, &community_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?; + + ActivityChannel::submit_activity( + SendActivityData::UpdateCommunity(local_user_view.person.clone(), community), + &context, + ) + .await?; + + build_community_response(&context, local_user_view, community_id).await } diff --git a/crates/api_crud/src/custom_emoji/create.rs b/crates/api_crud/src/custom_emoji/create.rs index 93e7114ae..589174455 100644 --- a/crates/api_crud/src/custom_emoji/create.rs +++ b/crates/api_crud/src/custom_emoji/create.rs @@ -1,5 +1,5 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{CreateCustomEmoji, CustomEmojiResponse}, @@ -13,41 +13,38 @@ use lemmy_db_schema::source::{ use lemmy_db_views::structs::CustomEmojiView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for CreateCustomEmoji { - type Response = CustomEmojiResponse; +#[tracing::instrument(skip(context))] +pub async fn create_custom_emoji( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreateCustomEmoji = self; - 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)?; - let local_site = LocalSite::read(&mut context.pool()).await?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let shortcode = sanitize_html(data.shortcode.to_lowercase().trim()); + let alt_text = sanitize_html(&data.alt_text); + let category = sanitize_html(&data.category); - let shortcode = sanitize_html(data.shortcode.to_lowercase().trim()); - let alt_text = sanitize_html(&data.alt_text); - let category = sanitize_html(&data.category); - - let emoji_form = CustomEmojiInsertForm::builder() - .local_site_id(local_site.id) - .shortcode(shortcode) - .alt_text(alt_text) - .category(category) - .image_url(data.clone().image_url.into()) + let emoji_form = CustomEmojiInsertForm::builder() + .local_site_id(local_site.id) + .shortcode(shortcode) + .alt_text(alt_text) + .category(category) + .image_url(data.clone().image_url.into()) + .build(); + let emoji = CustomEmoji::create(&mut context.pool(), &emoji_form).await?; + let mut keywords = vec![]; + for keyword in &data.keywords { + let keyword_form = CustomEmojiKeywordInsertForm::builder() + .custom_emoji_id(emoji.id) + .keyword(keyword.to_lowercase().trim().to_string()) .build(); - let emoji = CustomEmoji::create(&mut context.pool(), &emoji_form).await?; - let mut keywords = vec![]; - for keyword in &data.keywords { - let keyword_form = CustomEmojiKeywordInsertForm::builder() - .custom_emoji_id(emoji.id) - .keyword(keyword.to_lowercase().trim().to_string()) - .build(); - keywords.push(keyword_form); - } - CustomEmojiKeyword::create(&mut context.pool(), keywords).await?; - let view = CustomEmojiView::get(&mut context.pool(), emoji.id).await?; - Ok(CustomEmojiResponse { custom_emoji: view }) + keywords.push(keyword_form); } + CustomEmojiKeyword::create(&mut context.pool(), keywords).await?; + let view = CustomEmojiView::get(&mut context.pool(), emoji.id).await?; + Ok(Json(CustomEmojiResponse { custom_emoji: view })) } diff --git a/crates/api_crud/src/custom_emoji/delete.rs b/crates/api_crud/src/custom_emoji/delete.rs index 069129239..be88d310f 100644 --- a/crates/api_crud/src/custom_emoji/delete.rs +++ b/crates/api_crud/src/custom_emoji/delete.rs @@ -1,5 +1,5 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{DeleteCustomEmoji, DeleteCustomEmojiResponse}, @@ -8,24 +8,18 @@ use lemmy_api_common::{ use lemmy_db_schema::source::custom_emoji::CustomEmoji; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeleteCustomEmoji { - type Response = DeleteCustomEmojiResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_custom_emoji( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &DeleteCustomEmoji = self; - 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?; - Ok(DeleteCustomEmojiResponse { - id: data.id, - success: true, - }) - } + // Make sure user is an admin + is_admin(&local_user_view)?; + CustomEmoji::delete(&mut context.pool(), data.id).await?; + Ok(Json(DeleteCustomEmojiResponse { + id: data.id, + success: true, + })) } diff --git a/crates/api_crud/src/custom_emoji/mod.rs b/crates/api_crud/src/custom_emoji/mod.rs index b9d8b5577..fdb2f5561 100644 --- a/crates/api_crud/src/custom_emoji/mod.rs +++ b/crates/api_crud/src/custom_emoji/mod.rs @@ -1,3 +1,3 @@ -mod create; -mod delete; -mod update; +pub mod create; +pub mod delete; +pub mod update; diff --git a/crates/api_crud/src/custom_emoji/update.rs b/crates/api_crud/src/custom_emoji/update.rs index 93708c379..7a2056895 100644 --- a/crates/api_crud/src/custom_emoji/update.rs +++ b/crates/api_crud/src/custom_emoji/update.rs @@ -1,5 +1,5 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, custom_emoji::{CustomEmojiResponse, EditCustomEmoji}, @@ -13,40 +13,37 @@ use lemmy_db_schema::source::{ use lemmy_db_views::structs::CustomEmojiView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditCustomEmoji { - type Response = CustomEmojiResponse; +#[tracing::instrument(skip(context))] +pub async fn update_custom_emoji( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data: &EditCustomEmoji = self; - 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)?; - let local_site = LocalSite::read(&mut context.pool()).await?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let alt_text = sanitize_html(&data.alt_text); + let category = sanitize_html(&data.category); - let alt_text = sanitize_html(&data.alt_text); - let category = sanitize_html(&data.category); - - let emoji_form = CustomEmojiUpdateForm::builder() - .local_site_id(local_site.id) - .alt_text(alt_text) - .category(category) - .image_url(data.clone().image_url.into()) + let emoji_form = CustomEmojiUpdateForm::builder() + .local_site_id(local_site.id) + .alt_text(alt_text) + .category(category) + .image_url(data.clone().image_url.into()) + .build(); + let emoji = CustomEmoji::update(&mut context.pool(), data.id, &emoji_form).await?; + CustomEmojiKeyword::delete(&mut context.pool(), data.id).await?; + let mut keywords = vec![]; + for keyword in &data.keywords { + let keyword_form = CustomEmojiKeywordInsertForm::builder() + .custom_emoji_id(emoji.id) + .keyword(keyword.to_lowercase().trim().to_string()) .build(); - let emoji = CustomEmoji::update(&mut context.pool(), data.id, &emoji_form).await?; - CustomEmojiKeyword::delete(&mut context.pool(), data.id).await?; - let mut keywords = vec![]; - for keyword in &data.keywords { - let keyword_form = CustomEmojiKeywordInsertForm::builder() - .custom_emoji_id(emoji.id) - .keyword(keyword.to_lowercase().trim().to_string()) - .build(); - keywords.push(keyword_form); - } - CustomEmojiKeyword::create(&mut context.pool(), keywords).await?; - let view = CustomEmojiView::get(&mut context.pool(), emoji.id).await?; - Ok(CustomEmojiResponse { custom_emoji: view }) + keywords.push(keyword_form); } + CustomEmojiKeyword::create(&mut context.pool(), keywords).await?; + let view = CustomEmojiView::get(&mut context.pool(), emoji.id).await?; + Ok(Json(CustomEmojiResponse { custom_emoji: view })) } diff --git a/crates/api_crud/src/lib.rs b/crates/api_crud/src/lib.rs index edd5c46f2..aee3e8134 100644 --- a/crates/api_crud/src/lib.rs +++ b/crates/api_crud/src/lib.rs @@ -1,7 +1,3 @@ -use actix_web::web::Data; -use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; - pub mod comment; pub mod community; pub mod custom_emoji; @@ -9,10 +5,3 @@ pub mod post; pub mod private_message; pub mod site; pub mod user; - -#[async_trait::async_trait(?Send)] -pub trait PerformCrud { - type Response: serde::ser::Serialize + Send + Clone + Sync; - - async fn perform(&self, context: &Data) -> Result; -} diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 264cdbc82..dd88204a9 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -194,7 +194,5 @@ pub async fn create_post( } }; - Ok(Json( - build_post_response(&context, community_id, person_id, post_id).await?, - )) + 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 eaeb66c43..0d5eea886 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{DeletePost, PostResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, check_community_deleted_or_removed, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -12,52 +13,50 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::{LemmyError, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeletePost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &DeletePost = self; - 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?; - let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; - - // Dont delete it if its already been deleted. - if orig_post.deleted == data.deleted { - return Err(LemmyErrorType::CouldntUpdatePost)?; - } - - check_community_ban( - local_user_view.person.id, - orig_post.community_id, - &mut context.pool(), - ) - .await?; - check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; - - // Verify that only the creator can delete - if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(LemmyErrorType::NoPostEditAllowed)?; - } - - // Update the post - let post_id = data.post_id; - let deleted = data.deleted; - Post::update( - &mut context.pool(), - post_id, - &PostUpdateForm::builder().deleted(Some(deleted)).build(), - ) - .await?; - - build_post_response( - context, - orig_post.community_id, - local_user_view.person.id, - post_id, - ) - .await + // Dont delete it if its already been deleted. + if orig_post.deleted == data.deleted { + return Err(LemmyErrorType::CouldntUpdatePost)?; } + + check_community_ban( + local_user_view.person.id, + orig_post.community_id, + &mut context.pool(), + ) + .await?; + check_community_deleted_or_removed(orig_post.community_id, &mut context.pool()).await?; + + // Verify that only the creator can delete + if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { + return Err(LemmyErrorType::NoPostEditAllowed)?; + } + + // Update the post + let post = Post::update( + &mut context.pool(), + data.post_id, + &PostUpdateForm::builder() + .deleted(Some(data.deleted)) + .build(), + ) + .await?; + + let person_id = local_user_view.person.id; + ActivityChannel::submit_activity( + SendActivityData::DeletePost(post, local_user_view.person, data.0.clone()), + &context, + ) + .await?; + + build_post_response(&context, orig_post.community_id, person_id, data.post_id).await } diff --git a/crates/api_crud/src/post/remove.rs b/crates/api_crud/src/post/remove.rs index 7950d5047..4a87eb784 100644 --- a/crates/api_crud/src/post/remove.rs +++ b/crates/api_crud/src/post/remove.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::build_post_response, context::LemmyContext, post::{PostResponse, RemovePost}, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, is_mod_or_admin, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -15,58 +16,56 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for RemovePost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn remove_post( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &RemovePost = self; - 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?; - let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + check_community_ban( + local_user_view.person.id, + orig_post.community_id, + &mut context.pool(), + ) + .await?; - check_community_ban( - local_user_view.person.id, - orig_post.community_id, - &mut context.pool(), - ) - .await?; + // Verify that only the mods can remove + is_mod_or_admin( + &mut context.pool(), + local_user_view.person.id, + orig_post.community_id, + ) + .await?; - // Verify that only the mods can remove - is_mod_or_admin( - &mut context.pool(), - local_user_view.person.id, - orig_post.community_id, - ) - .await?; + // Update the post + let post_id = data.post_id; + let removed = data.removed; + let post = Post::update( + &mut context.pool(), + post_id, + &PostUpdateForm::builder().removed(Some(removed)).build(), + ) + .await?; - // Update the post - let post_id = data.post_id; - let removed = data.removed; - Post::update( - &mut context.pool(), - post_id, - &PostUpdateForm::builder().removed(Some(removed)).build(), - ) - .await?; + // Mod tables + let form = ModRemovePostForm { + mod_person_id: local_user_view.person.id, + post_id: data.post_id, + removed: Some(removed), + reason: data.reason.clone(), + }; + ModRemovePost::create(&mut context.pool(), &form).await?; - // Mod tables - let form = ModRemovePostForm { - mod_person_id: local_user_view.person.id, - post_id: data.post_id, - removed: Some(removed), - reason: data.reason.clone(), - }; - ModRemovePost::create(&mut context.pool(), &form).await?; + let person_id = local_user_view.person.id; + ActivityChannel::submit_activity( + SendActivityData::RemovePost(post, local_user_view.person, data.0), + &context, + ) + .await?; - build_post_response( - context, - orig_post.community_id, - local_user_view.person.id, - post_id, - ) - .await - } + build_post_response(&context, orig_post.community_id, person_id, post_id).await } diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 3341392bc..c831c88f1 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -113,13 +113,11 @@ pub async fn update_post( ActivityChannel::submit_activity(SendActivityData::UpdatePost(updated_post), &context).await?; - Ok(Json( - build_post_response( - context.deref(), - orig_post.community_id, - local_user_view.person.id, - post_id, - ) - .await?, - )) + build_post_response( + context.deref(), + orig_post.community_id, + local_user_view.person.id, + post_id, + ) + .await } diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 3b1a625f6..b9ac916f3 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -1,8 +1,9 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, private_message::{CreatePrivateMessage, PrivateMessageResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_person_block, generate_local_apub_endpoint, @@ -27,78 +28,77 @@ use lemmy_utils::{ utils::{slurs::remove_slurs, validation::is_valid_body_field}, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for CreatePrivateMessage { - type Response = PrivateMessageResponse; +#[tracing::instrument(skip(context))] +pub async fn create_private_message( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &CreatePrivateMessage = self; - 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(&data.content); + let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site)); + is_valid_body_field(&Some(content.clone()), false)?; - let content = sanitize_html(&data.content); - let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site)); - is_valid_body_field(&Some(content.clone()), false)?; + check_person_block( + local_user_view.person.id, + data.recipient_id, + &mut context.pool(), + ) + .await?; - check_person_block( - local_user_view.person.id, - data.recipient_id, - &mut context.pool(), - ) - .await?; + let private_message_form = PrivateMessageInsertForm::builder() + .content(content.clone()) + .creator_id(local_user_view.person.id) + .recipient_id(data.recipient_id) + .build(); - let private_message_form = PrivateMessageInsertForm::builder() - .content(content.clone()) - .creator_id(local_user_view.person.id) - .recipient_id(data.recipient_id) - .build(); - - let inserted_private_message = - PrivateMessage::create(&mut context.pool(), &private_message_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - - let inserted_private_message_id = inserted_private_message.id; - let protocol_and_hostname = context.settings().get_protocol_and_hostname(); - let apub_id = generate_local_apub_endpoint( - EndpointType::PrivateMessage, - &inserted_private_message_id.to_string(), - &protocol_and_hostname, - )?; - PrivateMessage::update( - &mut context.pool(), - inserted_private_message.id, - &PrivateMessageUpdateForm::builder() - .ap_id(Some(apub_id)) - .build(), - ) + let inserted_private_message = PrivateMessage::create(&mut context.pool(), &private_message_form) .await .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id).await?; + let inserted_private_message_id = inserted_private_message.id; + let protocol_and_hostname = context.settings().get_protocol_and_hostname(); + let apub_id = generate_local_apub_endpoint( + EndpointType::PrivateMessage, + &inserted_private_message_id.to_string(), + &protocol_and_hostname, + )?; + PrivateMessage::update( + &mut context.pool(), + inserted_private_message.id, + &PrivateMessageUpdateForm::builder() + .ap_id(Some(apub_id)) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - // Send email to the local recipient, if one exists - if view.recipient.local { - let recipient_id = data.recipient_id; - let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id).await?; - let lang = get_interface_language(&local_recipient); - let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); - let sender_name = &local_user_view.person.name; - send_email_to_user( - &local_recipient, - &lang.notification_private_message_subject(sender_name), - &lang.notification_private_message_body(inbox_link, &content, sender_name), - context.settings(), - ) - .await; - } + let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id).await?; - Ok(PrivateMessageResponse { - private_message_view: view, - }) + // Send email to the local recipient, if one exists + if view.recipient.local { + let recipient_id = data.recipient_id; + let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id).await?; + let lang = get_interface_language(&local_recipient); + let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); + let sender_name = &local_user_view.person.name; + send_email_to_user( + &local_recipient, + &lang.notification_private_message_subject(sender_name), + &lang.notification_private_message_body(inbox_link, &content, sender_name), + context.settings(), + ) + .await; } + + ActivityChannel::submit_activity( + SendActivityData::CreatePrivateMessage(view.clone()), + &context, + ) + .await?; + + Ok(Json(PrivateMessageResponse { + private_message_view: view, + })) } diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index c18e94c0a..7657a7ff7 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -1,8 +1,9 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, private_message::{DeletePrivateMessage, PrivateMessageResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::local_user_view_from_jwt, }; use lemmy_db_schema::{ @@ -12,42 +13,41 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeletePrivateMessage { - type Response = PrivateMessageResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_private_message( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &DeletePrivateMessage = self; - 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?; - if local_user_view.person.id != orig_private_message.creator_id { - return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; - } - - // Doing the update - let private_message_id = data.private_message_id; - let deleted = data.deleted; - PrivateMessage::update( - &mut context.pool(), - private_message_id, - &PrivateMessageUpdateForm::builder() - .deleted(Some(deleted)) - .build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; - Ok(PrivateMessageResponse { - private_message_view: view, - }) + // Checking permissions + let private_message_id = data.private_message_id; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + if local_user_view.person.id != orig_private_message.creator_id { + return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; } + + // Doing the update + let private_message_id = data.private_message_id; + let deleted = data.deleted; + let private_message = PrivateMessage::update( + &mut context.pool(), + private_message_id, + &PrivateMessageUpdateForm::builder() + .deleted(Some(deleted)) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; + + ActivityChannel::submit_activity( + SendActivityData::DeletePrivateMessage(local_user_view.person, private_message, data.deleted), + &context, + ) + .await?; + + let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + Ok(Json(PrivateMessageResponse { + private_message_view: view, + })) } diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 09b50540d..eb24d7c12 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -1,8 +1,9 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; 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}, }; use lemmy_db_schema::{ @@ -19,48 +20,47 @@ use lemmy_utils::{ utils::{slurs::remove_slurs, validation::is_valid_body_field}, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditPrivateMessage { - type Response = PrivateMessageResponse; +#[tracing::instrument(skip(context))] +pub async fn update_private_message( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &EditPrivateMessage = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; - - // Checking permissions - let private_message_id = data.private_message_id; - let orig_private_message = - PrivateMessage::read(&mut context.pool(), private_message_id).await?; - if local_user_view.person.id != orig_private_message.creator_id { - return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; - } - - // Doing the update - let content = sanitize_html(&data.content); - let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site)); - is_valid_body_field(&Some(content.clone()), false)?; - - let private_message_id = data.private_message_id; - PrivateMessage::update( - &mut context.pool(), - private_message_id, - &PrivateMessageUpdateForm::builder() - .content(Some(content)) - .updated(Some(Some(naive_now()))) - .build(), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; - - Ok(PrivateMessageResponse { - private_message_view: view, - }) + // Checking permissions + let private_message_id = data.private_message_id; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + if local_user_view.person.id != orig_private_message.creator_id { + return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; } + + // Doing the update + let content = sanitize_html(&data.content); + let content = remove_slurs(&content, &local_site_to_slur_regex(&local_site)); + is_valid_body_field(&Some(content.clone()), false)?; + + let private_message_id = data.private_message_id; + PrivateMessage::update( + &mut context.pool(), + private_message_id, + &PrivateMessageUpdateForm::builder() + .content(Some(content)) + .updated(Some(Some(naive_now()))) + .build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; + + let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + + ActivityChannel::submit_activity( + SendActivityData::UpdatePrivateMessage(view.clone()), + &context, + ) + .await?; + + Ok(Json(PrivateMessageResponse { + private_message_view: view, + })) } diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index f2af6940e..1665ba191 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -1,6 +1,5 @@ -use crate::PerformCrud; -use activitypub_federation::http_signatures::generate_actor_keypair; -use actix_web::web::Data; +use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair}; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, person::{LoginResponse, Register}, @@ -38,177 +37,173 @@ use lemmy_utils::{ }, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for Register { - type Response = LoginResponse; +#[tracing::instrument(skip(context))] +pub async fn register( + data: Json, + context: Data, +) -> Result, LemmyError> { + let site_view = SiteView::read_local(&mut context.pool()).await?; + let local_site = site_view.local_site; + let require_registration_application = + local_site.registration_mode == RegistrationMode::RequireApplication; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data: &Register = self; + if local_site.registration_mode == RegistrationMode::Closed { + return Err(LemmyErrorType::RegistrationClosed)?; + } - let site_view = SiteView::read_local(&mut context.pool()).await?; - let local_site = site_view.local_site; - let require_registration_application = - local_site.registration_mode == RegistrationMode::RequireApplication; + password_length_check(&data.password)?; + honeypot_check(&data.honeypot)?; - if local_site.registration_mode == RegistrationMode::Closed { - return Err(LemmyErrorType::RegistrationClosed)?; - } + if local_site.require_email_verification && data.email.is_none() { + return Err(LemmyErrorType::EmailRequired)?; + } - password_length_check(&data.password)?; - honeypot_check(&data.honeypot)?; + if local_site.site_setup && require_registration_application && data.answer.is_none() { + return Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?; + } - if local_site.require_email_verification && data.email.is_none() { - return Err(LemmyErrorType::EmailRequired)?; - } + // Make sure passwords match + if data.password != data.password_verify { + return Err(LemmyErrorType::PasswordsDoNotMatch)?; + } - if local_site.site_setup && require_registration_application && data.answer.is_none() { - return Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?; - } - - // Make sure passwords match - if data.password != data.password_verify { - return Err(LemmyErrorType::PasswordsDoNotMatch)?; - } - - if local_site.site_setup && local_site.captcha_enabled { - if let Some(captcha_uuid) = &data.captcha_uuid { - let uuid = uuid::Uuid::parse_str(captcha_uuid)?; - let check = CaptchaAnswer::check_captcha( - &mut context.pool(), - CheckCaptchaAnswer { - uuid, - answer: data.captcha_answer.clone().unwrap_or_default(), - }, - ) - .await?; - if !check { - return Err(LemmyErrorType::CaptchaIncorrect)?; - } - } else { + if local_site.site_setup && local_site.captcha_enabled { + if let Some(captcha_uuid) = &data.captcha_uuid { + let uuid = uuid::Uuid::parse_str(captcha_uuid)?; + let check = CaptchaAnswer::check_captcha( + &mut context.pool(), + CheckCaptchaAnswer { + uuid, + answer: data.captcha_answer.clone().unwrap_or_default(), + }, + ) + .await?; + if !check { return Err(LemmyErrorType::CaptchaIncorrect)?; } + } else { + return Err(LemmyErrorType::CaptchaIncorrect)?; } + } - let slur_regex = local_site_to_slur_regex(&local_site); - check_slurs(&data.username, &slur_regex)?; - check_slurs_opt(&data.answer, &slur_regex)?; - let username = sanitize_html(&data.username); + let slur_regex = local_site_to_slur_regex(&local_site); + check_slurs(&data.username, &slur_regex)?; + check_slurs_opt(&data.answer, &slur_regex)?; + let username = sanitize_html(&data.username); - let actor_keypair = generate_actor_keypair()?; - is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize)?; - let actor_id = generate_local_apub_endpoint( - EndpointType::Person, - &data.username, - &context.settings().get_protocol_and_hostname(), - )?; + let actor_keypair = generate_actor_keypair()?; + is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize)?; + let actor_id = generate_local_apub_endpoint( + EndpointType::Person, + &data.username, + &context.settings().get_protocol_and_hostname(), + )?; - if let Some(email) = &data.email { - if LocalUser::is_email_taken(&mut context.pool(), email).await? { - return Err(LemmyErrorType::EmailAlreadyExists)?; - } + if let Some(email) = &data.email { + if LocalUser::is_email_taken(&mut context.pool(), email).await? { + return Err(LemmyErrorType::EmailAlreadyExists)?; } + } - // We have to create both a person, and local_user + // We have to create both a person, and local_user - // Register the new person - let person_form = PersonInsertForm::builder() - .name(username) - .actor_id(Some(actor_id.clone())) - .private_key(Some(actor_keypair.private_key)) - .public_key(actor_keypair.public_key) - .inbox_url(Some(generate_inbox_url(&actor_id)?)) - .shared_inbox_url(Some(generate_shared_inbox_url(&actor_id)?)) - // If its the initial site setup, they are an admin - .admin(Some(!local_site.site_setup)) - .instance_id(site_view.site.instance_id) - .build(); + // Register the new person + let person_form = PersonInsertForm::builder() + .name(username) + .actor_id(Some(actor_id.clone())) + .private_key(Some(actor_keypair.private_key)) + .public_key(actor_keypair.public_key) + .inbox_url(Some(generate_inbox_url(&actor_id)?)) + .shared_inbox_url(Some(generate_shared_inbox_url(&actor_id)?)) + // If its the initial site setup, they are an admin + .admin(Some(!local_site.site_setup)) + .instance_id(site_view.site.instance_id) + .build(); - // insert the person - let inserted_person = Person::create(&mut context.pool(), &person_form) - .await - .with_lemmy_type(LemmyErrorType::UserAlreadyExists)?; + // insert the person + let inserted_person = Person::create(&mut context.pool(), &person_form) + .await + .with_lemmy_type(LemmyErrorType::UserAlreadyExists)?; - // Automatically set their application as accepted, if they created this with open registration. - // Also fixes a bug which allows users to log in when registrations are changed to closed. - let accepted_application = Some(!require_registration_application); + // Automatically set their application as accepted, if they created this with open registration. + // Also fixes a bug which allows users to log in when registrations are changed to closed. + let accepted_application = Some(!require_registration_application); - // Create the local user - let local_user_form = LocalUserInsertForm::builder() - .person_id(inserted_person.id) - .email(data.email.as_deref().map(str::to_lowercase)) - .password_encrypted(data.password.to_string()) - .show_nsfw(Some(data.show_nsfw)) - .accepted_application(accepted_application) - .default_listing_type(Some(local_site.default_post_listing_type)) - .build(); + // Create the local user + let local_user_form = LocalUserInsertForm::builder() + .person_id(inserted_person.id) + .email(data.email.as_deref().map(str::to_lowercase)) + .password_encrypted(data.password.to_string()) + .show_nsfw(Some(data.show_nsfw)) + .accepted_application(accepted_application) + .default_listing_type(Some(local_site.default_post_listing_type)) + .build(); - let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?; + let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?; - if local_site.site_setup && require_registration_application { - // Create the registration application - let form = RegistrationApplicationInsertForm { - local_user_id: inserted_local_user.id, - // We already made sure answer was not null above - answer: data.answer.clone().expect("must have an answer"), - }; - - RegistrationApplication::create(&mut context.pool(), &form).await?; - } - - // Email the admins - if local_site.application_email_admins { - send_new_applicant_email_to_admins(&data.username, &mut context.pool(), context.settings()) - .await?; - } - - let mut login_response = LoginResponse { - jwt: None, - registration_created: false, - verify_email_sent: false, + if local_site.site_setup && require_registration_application { + // Create the registration application + let form = RegistrationApplicationInsertForm { + local_user_id: inserted_local_user.id, + // We already made sure answer was not null above + answer: data.answer.clone().expect("must have an answer"), }; - // Log the user in directly if the site is not setup, or email verification and application aren't required - if !local_site.site_setup - || (!require_registration_application && !local_site.require_email_verification) - { - login_response.jwt = Some( - Claims::jwt( - inserted_local_user.id.0, - &context.secret().jwt_secret, - &context.settings().hostname, - )? - .into(), - ); - } else { - if local_site.require_email_verification { - let local_user_view = LocalUserView { - local_user: inserted_local_user, - person: inserted_person, - counts: PersonAggregates::default(), - }; - // we check at the beginning of this method that email is set - let email = local_user_view - .local_user - .email - .clone() - .expect("email was provided"); + RegistrationApplication::create(&mut context.pool(), &form).await?; + } - send_verification_email( - &local_user_view, - &email, - &mut context.pool(), - context.settings(), - ) - .await?; - login_response.verify_email_sent = true; - } + // Email the admins + if local_site.application_email_admins { + send_new_applicant_email_to_admins(&data.username, &mut context.pool(), context.settings()) + .await?; + } - if require_registration_application { - login_response.registration_created = true; - } + let mut login_response = LoginResponse { + jwt: None, + registration_created: false, + verify_email_sent: false, + }; + + // Log the user in directly if the site is not setup, or email verification and application aren't required + if !local_site.site_setup + || (!require_registration_application && !local_site.require_email_verification) + { + login_response.jwt = Some( + Claims::jwt( + inserted_local_user.id.0, + &context.secret().jwt_secret, + &context.settings().hostname, + )? + .into(), + ); + } else { + if local_site.require_email_verification { + let local_user_view = LocalUserView { + local_user: inserted_local_user, + person: inserted_person, + counts: PersonAggregates::default(), + }; + // we check at the beginning of this method that email is set + let email = local_user_view + .local_user + .email + .clone() + .expect("email was provided"); + + send_verification_email( + &local_user_view, + &email, + &mut context.pool(), + context.settings(), + ) + .await?; + login_response.verify_email_sent = true; } - Ok(login_response) + if require_registration_application { + login_response.registration_created = true; + } } + + Ok(Json(login_response)) } diff --git a/crates/api_crud/src/user/delete.rs b/crates/api_crud/src/user/delete.rs index 5a8b4d036..94c547b14 100644 --- a/crates/api_crud/src/user/delete.rs +++ b/crates/api_crud/src/user/delete.rs @@ -1,32 +1,36 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use bcrypt::verify; use lemmy_api_common::{ context::LemmyContext, person::{DeleteAccount, DeleteAccountResponse}, + send_activity::{ActivityChannel, SendActivityData}, utils::local_user_view_from_jwt, }; use lemmy_utils::error::{LemmyError, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl PerformCrud for DeleteAccount { - type Response = DeleteAccountResponse; +#[tracing::instrument(skip(context))] +pub async fn delete_account( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data = self; - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), context).await?; - - // Verify the password - let valid: bool = verify( - &data.password, - &local_user_view.local_user.password_encrypted, - ) - .unwrap_or(false); - if !valid { - return Err(LemmyErrorType::IncorrectLogin)?; - } - - Ok(DeleteAccountResponse {}) + // Verify the password + let valid: bool = verify( + &data.password, + &local_user_view.local_user.password_encrypted, + ) + .unwrap_or(false); + if !valid { + return Err(LemmyErrorType::IncorrectLogin)?; } + + ActivityChannel::submit_activity( + SendActivityData::DeleteUser(local_user_view.person), + &context, + ) + .await?; + + Ok(Json(DeleteAccountResponse {})) } diff --git a/crates/api_crud/src/user/mod.rs b/crates/api_crud/src/user/mod.rs index aeaae9ddd..da1aa3ace 100644 --- a/crates/api_crud/src/user/mod.rs +++ b/crates/api_crud/src/user/mod.rs @@ -1,2 +1,2 @@ -mod create; -mod delete; +pub mod create; +pub mod delete; diff --git a/crates/apub/src/activities/block/mod.rs b/crates/apub/src/activities/block/mod.rs index 7ee9ec177..e9986afc8 100644 --- a/crates/apub/src/activities/block/mod.rs +++ b/crates/apub/src/activities/block/mod.rs @@ -1,10 +1,9 @@ use crate::{ - objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson}, + objects::{community::ApubCommunity, instance::ApubSite}, protocol::{ activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser}, objects::{group::Group, instance::Instance}, }, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -12,19 +11,18 @@ use activitypub_federation::{ traits::{Actor, Object}, }; use chrono::NaiveDateTime; -use lemmy_api_common::{ - community::{BanFromCommunity, BanFromCommunityResponse}, - context::LemmyContext, - person::{BanPerson, BanPersonResponse}, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::{community::BanFromCommunity, context::LemmyContext, person::BanPerson}; use lemmy_db_schema::{ + newtypes::CommunityId, source::{community::Community, person::Person, site::Site}, traits::Crud, utils::DbPool, }; use lemmy_db_views::structs::SiteView; -use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + utils::time::naive_from_unix, +}; use serde::Deserialize; use url::Url; @@ -132,87 +130,74 @@ async fn generate_cc( }) } -#[async_trait::async_trait] -impl SendActivity for BanPerson { - type Response = BanPersonResponse; +pub(crate) async fn send_ban_from_site( + mod_: Person, + banned_user: Person, + data: BanPerson, + context: Data, +) -> Result<(), LemmyError> { + let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into()); + let expires = data.expires.map(naive_from_unix); - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let person = Person::read(&mut context.pool(), request.person_id).await?; - let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into()); - let expires = request.expires.map(naive_from_unix); - - // if the action affects a local user, federate to other instances - if person.local { - if request.ban { - BlockUser::send( - &site, - &person.into(), - &local_user_view.person.into(), - request.remove_data.unwrap_or(false), - request.reason.clone(), - expires, - context, - ) - .await - } else { - UndoBlockUser::send( - &site, - &person.into(), - &local_user_view.person.into(), - request.reason.clone(), - context, - ) - .await - } - } else { - Ok(()) - } - } -} - -#[async_trait::async_trait] -impl SendActivity for BanFromCommunity { - type Response = BanFromCommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community: ApubCommunity = Community::read(&mut context.pool(), request.community_id) - .await? - .into(); - let banned_person: ApubPerson = Person::read(&mut context.pool(), request.person_id) - .await? - .into(); - let expires = request.expires.map(naive_from_unix); - - if request.ban { + // if the action affects a local user, federate to other instances + if banned_user.local { + if data.ban { BlockUser::send( - &SiteOrCommunity::Community(community), - &banned_person, - &local_user_view.person.clone().into(), - request.remove_data.unwrap_or(false), - request.reason.clone(), + &site, + &banned_user.into(), + &mod_.into(), + data.remove_data.unwrap_or(false), + data.reason.clone(), expires, - context, + &context, ) .await } else { UndoBlockUser::send( - &SiteOrCommunity::Community(community), - &banned_person, - &local_user_view.person.clone().into(), - request.reason.clone(), - context, + &site, + &banned_user.into(), + &mod_.into(), + data.reason.clone(), + &context, ) .await } + } else { + Ok(()) + } +} + +pub(crate) async fn send_ban_from_community( + mod_: Person, + community_id: CommunityId, + banned_person: Person, + data: BanFromCommunity, + context: Data, +) -> LemmyResult<()> { + let community: ApubCommunity = Community::read(&mut context.pool(), community_id) + .await? + .into(); + let expires = data.expires.map(naive_from_unix); + + if data.ban { + BlockUser::send( + &SiteOrCommunity::Community(community), + &banned_person.into(), + &mod_.into(), + data.remove_data.unwrap_or(false), + data.reason.clone(), + expires, + &context, + ) + .await + } else { + UndoBlockUser::send( + &SiteOrCommunity::Community(community), + &banned_person.into(), + &mod_.into(), + data.reason.clone(), + &context, + ) + .await } } diff --git a/crates/apub/src/activities/community/collection_add.rs b/crates/apub/src/activities/community/collection_add.rs index c36a8f0da..e03ded2b3 100644 --- a/crates/apub/src/activities/community/collection_add.rs +++ b/crates/apub/src/activities/community/collection_add.rs @@ -13,7 +13,6 @@ use crate::{ activities::community::{collection_add::CollectionAdd, collection_remove::CollectionRemove}, InCommunity, }, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -22,13 +21,12 @@ use activitypub_federation::{ traits::{ActivityHandler, Actor}, }; use lemmy_api_common::{ - community::{AddModToCommunity, AddModToCommunityResponse}, context::LemmyContext, - post::{FeaturePost, PostResponse}, - utils::{generate_featured_url, generate_moderators_url, local_user_view_from_jwt}, + utils::{generate_featured_url, generate_moderators_url}, }; use lemmy_db_schema::{ impls::community::CollectionType, + newtypes::{CommunityId, PersonId}, source::{ community::{Community, CommunityModerator, CommunityModeratorForm}, moderator::{ModAddCommunity, ModAddCommunityForm}, @@ -165,61 +163,41 @@ impl ActivityHandler for CollectionAdd { } } -#[async_trait::async_trait] -impl SendActivity for AddModToCommunity { - type Response = AddModToCommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community: ApubCommunity = Community::read(&mut context.pool(), request.community_id) - .await? - .into(); - let updated_mod: ApubPerson = Person::read(&mut context.pool(), request.person_id) - .await? - .into(); - if request.added { - CollectionAdd::send_add_mod( - &community, - &updated_mod, - &local_user_view.person.into(), - context, - ) - .await - } else { - CollectionRemove::send_remove_mod( - &community, - &updated_mod, - &local_user_view.person.into(), - context, - ) - .await - } +pub(crate) async fn send_add_mod_to_community( + actor: Person, + community_id: CommunityId, + updated_mod_id: PersonId, + added: bool, + context: Data, +) -> Result<(), LemmyError> { + let actor: ApubPerson = actor.into(); + let community: ApubCommunity = Community::read(&mut context.pool(), community_id) + .await? + .into(); + let updated_mod: ApubPerson = Person::read(&mut context.pool(), updated_mod_id) + .await? + .into(); + if added { + CollectionAdd::send_add_mod(&community, &updated_mod, &actor, &context).await + } else { + CollectionRemove::send_remove_mod(&community, &updated_mod, &actor, &context).await } } -#[async_trait::async_trait] -impl SendActivity for FeaturePost { - type Response = PostResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), response.post_view.community.id) - .await? - .into(); - let post = response.post_view.post.clone().into(); - let person = local_user_view.person.into(); - if request.featured { - CollectionAdd::send_add_featured_post(&community, &post, &person, context).await - } else { - CollectionRemove::send_remove_featured_post(&community, &post, &person, context).await - } +pub(crate) async fn send_feature_post( + post: Post, + actor: Person, + featured: bool, + context: Data, +) -> Result<(), LemmyError> { + let actor: ApubPerson = actor.into(); + let post: ApubPost = post.into(); + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .into(); + if featured { + CollectionAdd::send_add_featured_post(&community, &post, &actor, &context).await + } else { + CollectionRemove::send_remove_featured_post(&community, &post, &actor, &context).await } } diff --git a/crates/apub/src/activities/community/lock_page.rs b/crates/apub/src/activities/community/lock_page.rs index 94135ede9..2ceb18384 100644 --- a/crates/apub/src/activities/community/lock_page.rs +++ b/crates/apub/src/activities/community/lock_page.rs @@ -9,25 +9,23 @@ use crate::{ }, activity_lists::AnnouncableActivities, insert_received_activity, + objects::community::ApubCommunity, protocol::{ activities::community::lock_page::{LockPage, LockType, UndoLockPage}, InCommunity, }, - SendActivity, }; use activitypub_federation::{ config::Data, + fetch::object_id::ObjectId, kinds::{activity::UndoType, public}, traits::ActivityHandler, }; -use lemmy_api_common::{ - context::LemmyContext, - post::{LockPost, PostResponse}, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ source::{ community::Community, + person::Person, post::{Post, PostUpdateForm}, }, traits::Crud, @@ -102,59 +100,47 @@ impl ActivityHandler for UndoLockPage { } } -#[async_trait::async_trait] -impl SendActivity for LockPost { - type Response = PostResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; +pub(crate) async fn send_lock_post( + post: Post, + actor: Person, + locked: bool, + context: Data, +) -> Result<(), LemmyError> { + let community: ApubCommunity = Community::read(&mut context.pool(), post.community_id) + .await? + .into(); + let id = generate_activity_id( + LockType::Lock, + &context.settings().get_protocol_and_hostname(), + )?; + let community_id = community.actor_id.inner().clone(); + let lock = LockPage { + actor: actor.actor_id.clone().into(), + to: vec![public()], + object: ObjectId::from(post.ap_id), + cc: vec![community_id.clone()], + kind: LockType::Lock, + id, + audience: Some(community_id.into()), + }; + let activity = if locked { + AnnouncableActivities::LockPost(lock) + } else { let id = generate_activity_id( - LockType::Lock, + UndoType::Undo, &context.settings().get_protocol_and_hostname(), )?; - let community_id = response.post_view.community.actor_id.clone(); - let actor = local_user_view.person.actor_id.clone().into(); - let lock = LockPage { - actor, + let undo = UndoLockPage { + actor: lock.actor.clone(), to: vec![public()], - object: response.post_view.post.ap_id.clone().into(), - cc: vec![community_id.clone().into()], - kind: LockType::Lock, + cc: lock.cc.clone(), + kind: UndoType::Undo, id, - audience: Some(community_id.into()), + audience: lock.audience.clone(), + object: lock, }; - let activity = if request.locked { - AnnouncableActivities::LockPost(lock) - } else { - let id = generate_activity_id( - UndoType::Undo, - &context.settings().get_protocol_and_hostname(), - )?; - let undo = UndoLockPage { - actor: lock.actor.clone(), - to: vec![public()], - cc: lock.cc.clone(), - kind: UndoType::Undo, - id, - audience: lock.audience.clone(), - object: lock, - }; - AnnouncableActivities::UndoLockPost(undo) - }; - let community = Community::read(&mut context.pool(), response.post_view.community.id).await?; - send_activity_in_community( - activity, - &local_user_view.person.into(), - &community.into(), - vec![], - true, - context, - ) - .await?; - Ok(()) - } + AnnouncableActivities::UndoLockPost(undo) + }; + send_activity_in_community(activity, &actor.into(), &community, vec![], true, &context).await?; + Ok(()) } diff --git a/crates/apub/src/activities/community/report.rs b/crates/apub/src/activities/community/report.rs index 22a8c12be..a17df7119 100644 --- a/crates/apub/src/activities/community/report.rs +++ b/crates/apub/src/activities/community/report.rs @@ -4,7 +4,6 @@ use crate::{ objects::{community::ApubCommunity, person::ApubPerson}, protocol::{activities::community::report::Report, InCommunity}, PostOrComment, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -12,15 +11,12 @@ use activitypub_federation::{ kinds::activity::FlagType, traits::{ActivityHandler, Actor}, }; -use lemmy_api_common::{ - comment::{CommentReportResponse, CreateCommentReport}, - context::LemmyContext, - post::{CreatePostReport, PostReportResponse}, - utils::{local_user_view_from_jwt, sanitize_html}, -}; +use lemmy_api_common::{context::LemmyContext, utils::sanitize_html}; use lemmy_db_schema::{ source::{ comment_report::{CommentReport, CommentReportForm}, + community::Community, + person::Person, post_report::{PostReport, PostReportForm}, }, traits::Reportable, @@ -28,58 +24,17 @@ use lemmy_db_schema::{ use lemmy_utils::error::LemmyError; use url::Url; -#[async_trait::async_trait] -impl SendActivity for CreatePostReport { - type Response = PostReportResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - Report::send( - ObjectId::from(response.post_report_view.post.ap_id.clone()), - &local_user_view.person.into(), - ObjectId::from(response.post_report_view.community.actor_id.clone()), - request.reason.to_string(), - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for CreateCommentReport { - type Response = CommentReportResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - Report::send( - ObjectId::from(response.comment_report_view.comment.ap_id.clone()), - &local_user_view.person.into(), - ObjectId::from(response.comment_report_view.community.actor_id.clone()), - request.reason.to_string(), - context, - ) - .await - } -} - impl Report { #[tracing::instrument(skip_all)] - async fn send( + pub(crate) async fn send( object_id: ObjectId, - actor: &ApubPerson, - community_id: ObjectId, + actor: Person, + community: Community, reason: String, - context: &Data, + context: Data, ) -> Result<(), LemmyError> { - let community = community_id.dereference_local(context).await?; + let actor: ApubPerson = actor.into(); + let community: ApubCommunity = community.into(); let kind = FlagType::Flag; let id = generate_activity_id( kind.clone(), @@ -96,7 +51,7 @@ impl Report { }; let inbox = vec![community.shared_inbox_or_inbox()]; - send_lemmy_activity(context, report, actor, inbox, false).await + send_lemmy_activity(&context, report, &actor, inbox, false).await } } diff --git a/crates/apub/src/activities/community/update.rs b/crates/apub/src/activities/community/update.rs index fe2477d6e..c3b2a2ae1 100644 --- a/crates/apub/src/activities/community/update.rs +++ b/crates/apub/src/activities/community/update.rs @@ -10,61 +10,43 @@ use crate::{ insert_received_activity, objects::{community::ApubCommunity, person::ApubPerson}, protocol::{activities::community::update::UpdateCommunity, InCommunity}, - SendActivity, }; use activitypub_federation::{ config::Data, kinds::{activity::UpdateType, public}, traits::{ActivityHandler, Actor, Object}, }; -use lemmy_api_common::{ - community::{CommunityResponse, EditCommunity, HideCommunity}, - context::LemmyContext, - utils::local_user_view_from_jwt, +use lemmy_api_common::context::LemmyContext; +use lemmy_db_schema::{ + source::{community::Community, person::Person}, + traits::Crud, }; -use lemmy_db_schema::{source::community::Community, traits::Crud}; use lemmy_utils::error::LemmyError; use url::Url; -#[async_trait::async_trait] -impl SendActivity for EditCommunity { - type Response = CommunityResponse; +pub(crate) async fn send_update_community( + community: Community, + actor: Person, + context: Data, +) -> Result<(), LemmyError> { + let community: ApubCommunity = community.into(); + let actor: ApubPerson = actor.into(); + let id = generate_activity_id( + UpdateType::Update, + &context.settings().get_protocol_and_hostname(), + )?; + let update = UpdateCommunity { + actor: actor.id().into(), + to: vec![public()], + object: Box::new(community.clone().into_json(&context).await?), + cc: vec![community.id()], + kind: UpdateType::Update, + id: id.clone(), + audience: Some(community.id().into()), + }; - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), request.community_id).await?; - UpdateCommunity::send(community.into(), &local_user_view.person.into(), context).await - } -} - -impl UpdateCommunity { - #[tracing::instrument(skip_all)] - pub async fn send( - community: ApubCommunity, - actor: &ApubPerson, - context: &Data, - ) -> Result<(), LemmyError> { - let id = generate_activity_id( - UpdateType::Update, - &context.settings().get_protocol_and_hostname(), - )?; - let update = UpdateCommunity { - actor: actor.id().into(), - to: vec![public()], - object: Box::new(community.clone().into_json(context).await?), - cc: vec![community.id()], - kind: UpdateType::Update, - id: id.clone(), - audience: Some(community.id().into()), - }; - - let activity = AnnouncableActivities::UpdateCommunity(update); - send_activity_in_community(activity, actor, &community, vec![], true, context).await - } + let activity = AnnouncableActivities::UpdateCommunity(update); + send_activity_in_community(activity, &actor, &community, vec![], true, &context).await } #[async_trait::async_trait] @@ -101,18 +83,3 @@ impl ActivityHandler for UpdateCommunity { Ok(()) } } - -#[async_trait::async_trait] -impl SendActivity for HideCommunity { - type Response = CommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), request.community_id).await?; - UpdateCommunity::send(community.into(), &local_user_view.person.into(), context).await - } -} diff --git a/crates/apub/src/activities/create_or_update/private_message.rs b/crates/apub/src/activities/create_or_update/private_message.rs index 3eaad2f71..77a430c3c 100644 --- a/crates/apub/src/activities/create_or_update/private_message.rs +++ b/crates/apub/src/activities/create_or_update/private_message.rs @@ -6,92 +6,40 @@ use crate::{ create_or_update::chat_message::CreateOrUpdateChatMessage, CreateOrUpdateType, }, - SendActivity, }; use activitypub_federation::{ config::Data, protocol::verification::verify_domains_match, traits::{ActivityHandler, Actor, Object}, }; -use lemmy_api_common::{ - context::LemmyContext, - private_message::{CreatePrivateMessage, EditPrivateMessage, PrivateMessageResponse}, -}; -use lemmy_db_schema::{ - newtypes::PersonId, - source::{person::Person, private_message::PrivateMessage}, - traits::Crud, -}; +use lemmy_api_common::context::LemmyContext; +use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::error::LemmyError; use url::Url; -#[async_trait::async_trait] -impl SendActivity for CreatePrivateMessage { - type Response = PrivateMessageResponse; +pub(crate) async fn send_create_or_update_pm( + pm_view: PrivateMessageView, + kind: CreateOrUpdateType, + context: Data, +) -> Result<(), LemmyError> { + let actor: ApubPerson = pm_view.creator.into(); + let recipient: ApubPerson = pm_view.recipient.into(); - async fn send_activity( - _request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - CreateOrUpdateChatMessage::send( - &response.private_message_view.private_message, - response.private_message_view.creator.id, - CreateOrUpdateType::Create, - context, - ) - .await - } -} -#[async_trait::async_trait] -impl SendActivity for EditPrivateMessage { - type Response = PrivateMessageResponse; - - async fn send_activity( - _request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - CreateOrUpdateChatMessage::send( - &response.private_message_view.private_message, - response.private_message_view.creator.id, - CreateOrUpdateType::Update, - context, - ) - .await - } -} - -impl CreateOrUpdateChatMessage { - #[tracing::instrument(skip_all)] - async fn send( - private_message: &PrivateMessage, - sender_id: PersonId, - kind: CreateOrUpdateType, - context: &Data, - ) -> Result<(), LemmyError> { - let recipient_id = private_message.recipient_id; - let sender: ApubPerson = Person::read(&mut context.pool(), sender_id).await?.into(); - let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id) - .await? - .into(); - - let id = generate_activity_id( - kind.clone(), - &context.settings().get_protocol_and_hostname(), - )?; - let create_or_update = CreateOrUpdateChatMessage { - id: id.clone(), - actor: sender.id().into(), - to: [recipient.id().into()], - object: ApubPrivateMessage(private_message.clone()) - .into_json(context) - .await?, - kind, - }; - let inbox = vec![recipient.shared_inbox_or_inbox()]; - send_lemmy_activity(context, create_or_update, &sender, inbox, true).await - } + let id = generate_activity_id( + kind.clone(), + &context.settings().get_protocol_and_hostname(), + )?; + let create_or_update = CreateOrUpdateChatMessage { + id: id.clone(), + actor: actor.id().into(), + to: [recipient.id().into()], + object: ApubPrivateMessage(pm_view.private_message.clone()) + .into_json(&context) + .await?, + kind, + }; + let inbox = vec![recipient.shared_inbox_or_inbox()]; + send_lemmy_activity(&context, create_or_update, &actor, inbox, true).await } #[async_trait::async_trait] diff --git a/crates/apub/src/activities/deletion/delete_user.rs b/crates/apub/src/activities/deletion/delete_user.rs index b388ed9e1..cf37dc5ab 100644 --- a/crates/apub/src/activities/deletion/delete_user.rs +++ b/crates/apub/src/activities/deletion/delete_user.rs @@ -3,7 +3,6 @@ use crate::{ insert_received_activity, objects::{instance::remote_instance_inboxes, person::ApubPerson}, protocol::activities::deletion::delete_user::DeleteUser, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -11,50 +10,37 @@ use activitypub_federation::{ protocol::verification::verify_urls_match, traits::{ActivityHandler, Actor}, }; -use lemmy_api_common::{ - context::LemmyContext, - person::{DeleteAccount, DeleteAccountResponse}, - utils::{delete_user_account, local_user_view_from_jwt}, -}; +use lemmy_api_common::{context::LemmyContext, utils::delete_user_account}; +use lemmy_db_schema::source::person::Person; use lemmy_utils::error::LemmyError; use url::Url; -#[async_trait::async_trait] -impl SendActivity for DeleteAccount { - type Response = DeleteAccountResponse; +pub async fn delete_user(person: Person, context: Data) -> Result<(), LemmyError> { + let actor: ApubPerson = person.into(); + delete_user_account( + actor.id, + &mut context.pool(), + context.settings(), + context.client(), + ) + .await?; - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let actor: ApubPerson = local_user_view.person.into(); - delete_user_account( - actor.id, - &mut context.pool(), - context.settings(), - context.client(), - ) - .await?; + let id = generate_activity_id( + DeleteType::Delete, + &context.settings().get_protocol_and_hostname(), + )?; + let delete = DeleteUser { + actor: actor.id().into(), + to: vec![public()], + object: actor.id().into(), + kind: DeleteType::Delete, + id: id.clone(), + cc: vec![], + }; - let id = generate_activity_id( - DeleteType::Delete, - &context.settings().get_protocol_and_hostname(), - )?; - let delete = DeleteUser { - actor: actor.id().into(), - to: vec![public()], - object: actor.id().into(), - kind: DeleteType::Delete, - id: id.clone(), - cc: vec![], - }; - - let inboxes = remote_instance_inboxes(&mut context.pool()).await?; - send_lemmy_activity(context, delete, &actor, inboxes, true).await?; - Ok(()) - } + let inboxes = remote_instance_inboxes(&mut context.pool()).await?; + send_lemmy_activity(&context, delete, &actor, inboxes, true).await?; + Ok(()) } /// This can be separate from Delete activity because it doesn't need to be handled in shared inbox diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index c571ac22b..535a2af1a 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -19,7 +19,6 @@ use crate::{ activities::deletion::{delete::Delete, undo_delete::UndoDelete}, InCommunity, }, - SendActivity, }; use activitypub_federation::{ config::Data, @@ -28,14 +27,9 @@ use activitypub_federation::{ protocol::verification::verify_domains_match, traits::{Actor, Object}, }; -use lemmy_api_common::{ - community::{CommunityResponse, DeleteCommunity, RemoveCommunity}, - context::LemmyContext, - post::{DeletePost, PostResponse, RemovePost}, - private_message::{DeletePrivateMessage, PrivateMessageResponse}, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ + newtypes::CommunityId, source::{ comment::{Comment, CommentUpdateForm}, community::{Community, CommunityUpdateForm}, @@ -53,122 +47,6 @@ pub mod delete; pub mod delete_user; pub mod undo_delete; -#[async_trait::async_trait] -impl SendActivity for DeletePost { - type Response = PostResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), response.post_view.community.id).await?; - let deletable = DeletableObjects::Post(response.post_view.post.clone().into()); - send_apub_delete_in_community( - local_user_view.person, - community, - deletable, - None, - request.deleted, - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for RemovePost { - type Response = PostResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), response.post_view.community.id).await?; - let deletable = DeletableObjects::Post(response.post_view.post.clone().into()); - send_apub_delete_in_community( - local_user_view.person, - community, - deletable, - request.reason.clone().or_else(|| Some(String::new())), - request.removed, - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for DeletePrivateMessage { - type Response = PrivateMessageResponse; - - async fn send_activity( - request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - send_apub_delete_private_message( - &local_user_view.person.into(), - response.private_message_view.private_message.clone(), - request.deleted, - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for DeleteCommunity { - type Response = CommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), request.community_id).await?; - let deletable = DeletableObjects::Community(community.clone().into()); - send_apub_delete_in_community( - local_user_view.person, - community, - deletable, - None, - request.deleted, - context, - ) - .await - } -} - -#[async_trait::async_trait] -impl SendActivity for RemoveCommunity { - type Response = CommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), request.community_id).await?; - let deletable = DeletableObjects::Community(community.clone().into()); - send_apub_delete_in_community( - local_user_view.person, - community, - deletable, - request.reason.clone().or_else(|| Some(String::new())), - request.removed, - context, - ) - .await - } -} - /// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this /// action was done by a normal user. #[tracing::instrument(skip_all)] @@ -200,12 +78,44 @@ pub(crate) async fn send_apub_delete_in_community( .await } +/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this +/// action was done by a normal user. #[tracing::instrument(skip_all)] -async fn send_apub_delete_private_message( +pub(crate) async fn send_apub_delete_in_community_new( + actor: Person, + community_id: CommunityId, + object: DeletableObjects, + reason: Option, + deleted: bool, + context: Data, +) -> Result<(), LemmyError> { + let community = Community::read(&mut context.pool(), community_id).await?; + let actor = ApubPerson::from(actor); + let is_mod_action = reason.is_some(); + let activity = if deleted { + let delete = Delete::new(&actor, object, public(), Some(&community), reason, &context)?; + AnnouncableActivities::Delete(delete) + } else { + let undo = UndoDelete::new(&actor, object, public(), Some(&community), reason, &context)?; + AnnouncableActivities::UndoDelete(undo) + }; + send_activity_in_community( + activity, + &actor, + &community.into(), + vec![], + is_mod_action, + &context, + ) + .await +} + +#[tracing::instrument(skip_all)] +pub(crate) async fn send_apub_delete_private_message( actor: &ApubPerson, pm: PrivateMessage, deleted: bool, - context: &Data, + context: Data, ) -> Result<(), LemmyError> { let recipient_id = pm.recipient_id; let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id) @@ -215,11 +125,11 @@ async fn send_apub_delete_private_message( let deletable = DeletableObjects::PrivateMessage(pm.into()); let inbox = vec![recipient.shared_inbox_or_inbox()]; if deleted { - let delete = Delete::new(actor, deletable, recipient.id(), None, None, context)?; - send_lemmy_activity(context, delete, actor, inbox, true).await?; + let delete = Delete::new(actor, deletable, recipient.id(), None, None, &context)?; + send_lemmy_activity(&context, delete, actor, inbox, true).await?; } else { - let undo = UndoDelete::new(actor, deletable, recipient.id(), None, None, context)?; - send_lemmy_activity(context, undo, actor, inbox, true).await?; + let undo = UndoDelete::new(actor, deletable, recipient.id(), None, None, &context)?; + send_lemmy_activity(&context, undo, actor, inbox, true).await?; }; Ok(()) } diff --git a/crates/apub/src/activities/following/follow.rs b/crates/apub/src/activities/following/follow.rs index 2f0f5037a..d64041b94 100644 --- a/crates/apub/src/activities/following/follow.rs +++ b/crates/apub/src/activities/following/follow.rs @@ -8,12 +8,7 @@ use crate::{ fetcher::user_or_community::UserOrCommunity, insert_received_activity, objects::{community::ApubCommunity, person::ApubPerson}, - protocol::activities::following::{ - accept::AcceptFollow, - follow::Follow, - undo_follow::UndoFollow, - }, - SendActivity, + protocol::activities::following::{accept::AcceptFollow, follow::Follow}, }; use activitypub_federation::{ config::Data, @@ -21,17 +16,13 @@ use activitypub_federation::{ protocol::verification::verify_urls_match, traits::{ActivityHandler, Actor}, }; -use lemmy_api_common::{ - community::{BlockCommunity, BlockCommunityResponse}, - context::LemmyContext, - utils::local_user_view_from_jwt, -}; +use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ source::{ - community::{Community, CommunityFollower, CommunityFollowerForm}, + community::{CommunityFollower, CommunityFollowerForm}, person::{PersonFollower, PersonFollowerForm}, }, - traits::{Crud, Followable}, + traits::Followable, }; use lemmy_utils::error::LemmyError; use url::Url; @@ -128,18 +119,3 @@ impl ActivityHandler for Follow { AcceptFollow::send(self, context).await } } - -#[async_trait::async_trait] -impl SendActivity for BlockCommunity { - type Response = BlockCommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let community = Community::read(&mut context.pool(), request.community_id).await?; - UndoFollow::send(&local_user_view.person.into(), &community.into(), context).await - } -} diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 780755766..885abc603 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -1,11 +1,25 @@ use self::following::send_follow_community; use crate::{ activities::{ - deletion::{send_apub_delete_in_community, DeletableObjects}, + block::{send_ban_from_community, send_ban_from_site}, + community::{ + collection_add::{send_add_mod_to_community, send_feature_post}, + lock_page::send_lock_post, + update::send_update_community, + }, + create_or_update::private_message::send_create_or_update_pm, + deletion::{ + delete_user::delete_user, + send_apub_delete_in_community, + send_apub_delete_in_community_new, + send_apub_delete_private_message, + DeletableObjects, + }, voting::send_like_activity, }, objects::{community::ApubCommunity, person::ApubPerson}, protocol::activities::{ + community::report::Report, create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage}, CreateOrUpdateType, }, @@ -229,14 +243,46 @@ pub async fn match_outgoing_activities( let fed_task = async { use SendActivityData::*; match data { - CreatePost(post) | UpdatePost(post) => { + CreatePost(post) => { let creator_id = post.creator_id; CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Create, context).await } - CreateComment(comment) | UpdateComment(comment) => { + UpdatePost(post) => { + let creator_id = post.creator_id; + CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Update, context).await + } + DeletePost(post, person, data) => { + send_apub_delete_in_community_new( + person, + post.community_id, + DeletableObjects::Post(post.into()), + None, + data.deleted, + context, + ) + .await + } + RemovePost(post, person, data) => { + send_apub_delete_in_community_new( + person, + post.community_id, + DeletableObjects::Post(post.into()), + data.reason.or_else(|| Some(String::new())), + data.removed, + context, + ) + .await + } + LockPost(post, actor, locked) => send_lock_post(post, actor, locked, context).await, + FeaturePost(post, actor, featured) => send_feature_post(post, actor, featured, context).await, + CreateComment(comment) => { let creator_id = comment.creator_id; CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Create, context).await } + UpdateComment(comment) => { + let creator_id = comment.creator_id; + CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Update, context).await + } DeleteComment(comment, actor, community) => { let is_deleted = comment.deleted; let deletable = DeletableObjects::Comment(comment.into()); @@ -251,9 +297,46 @@ pub async fn match_outgoing_activities( LikePostOrComment(object_id, person, community, score) => { send_like_activity(object_id, person, community, score, context).await } - SendActivityData::FollowCommunity(community, person, follow) => { + FollowCommunity(community, person, follow) => { send_follow_community(community, person, follow, &context).await } + UpdateCommunity(actor, community) => send_update_community(community, actor, context).await, + DeleteCommunity(actor, community, removed) => { + let deletable = DeletableObjects::Community(community.clone().into()); + send_apub_delete_in_community(actor, community, deletable, None, removed, &context).await + } + RemoveCommunity(actor, community, reason, removed) => { + let deletable = DeletableObjects::Community(community.clone().into()); + send_apub_delete_in_community( + actor, + community, + deletable, + reason.clone().or_else(|| Some(String::new())), + removed, + &context, + ) + .await + } + AddModToCommunity(actor, community_id, updated_mod_id, added) => { + send_add_mod_to_community(actor, community_id, updated_mod_id, added, context).await + } + BanFromCommunity(mod_, community_id, target, data) => { + send_ban_from_community(mod_, community_id, target, data, context).await + } + BanFromSite(mod_, target, data) => send_ban_from_site(mod_, target, data, context).await, + CreatePrivateMessage(pm) => { + send_create_or_update_pm(pm, CreateOrUpdateType::Create, context).await + } + UpdatePrivateMessage(pm) => { + send_create_or_update_pm(pm, CreateOrUpdateType::Update, context).await + } + DeletePrivateMessage(person, pm, deleted) => { + send_apub_delete_private_message(&person.into(), pm, deleted, context).await + } + DeleteUser(person) => delete_user(person, context).await, + CreateReport(url, actor, community, reason) => { + Report::send(ObjectId::from(url), actor, community, reason, context).await + } } }; if *SYNCHRONOUS_FEDERATION { diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index dccf18dd4..f4a137d9a 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -1,33 +1,30 @@ use actix_web::{guard, web, Error, HttpResponse, Result}; use lemmy_api::{ comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment}, - comment_report::{list::list_comment_reports, resolve::resolve_comment_report}, - community::follow::follow_community, - local_user::notifications::mark_reply_read::mark_reply_as_read, - post::like::like_post, + comment_report::{ + create::create_comment_report, + list::list_comment_reports, + resolve::resolve_comment_report, + }, + community::{ + add_mod::add_mod_to_community, + ban::ban_from_community, + block::block_community, + follow::follow_community, + hide::hide_community, + }, + local_user::{ban_person::ban_from_site, notifications::mark_reply_read::mark_reply_as_read}, + post::{feature::feature_post, like::like_post, lock::lock_post}, + post_report::create::create_post_report, Perform, }; use lemmy_api_common::{ - comment::CreateCommentReport, - community::{ - AddModToCommunity, - BanFromCommunity, - BlockCommunity, - CreateCommunity, - DeleteCommunity, - EditCommunity, - HideCommunity, - RemoveCommunity, - TransferCommunity, - }, + community::TransferCommunity, context::LemmyContext, - custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji}, person::{ AddAdmin, - BanPerson, BlockPerson, ChangePassword, - DeleteAccount, GetBannedPersons, GetCaptcha, GetPersonMentions, @@ -39,27 +36,12 @@ use lemmy_api_common::{ MarkPersonMentionAsRead, PasswordChangeAfterReset, PasswordReset, - Register, SaveUserSettings, VerifyEmail, }, - post::{ - CreatePostReport, - DeletePost, - FeaturePost, - GetSiteMetadata, - ListPostReports, - LockPost, - MarkPostAsRead, - RemovePost, - ResolvePostReport, - SavePost, - }, + post::{GetSiteMetadata, ListPostReports, MarkPostAsRead, ResolvePostReport, SavePost}, private_message::{ - CreatePrivateMessage, CreatePrivateMessageReport, - DeletePrivateMessage, - EditPrivateMessage, ListPrivateMessageReports, MarkPrivateMessageAsRead, ResolvePrivateMessageReport, @@ -85,11 +67,33 @@ use lemmy_api_crud::{ remove::remove_comment, update::update_comment, }, - community::list::list_communities, - post::{create::create_post, read::get_post, update::update_post}, - private_message::read::get_private_message, + community::{ + create::create_community, + delete::delete_community, + list::list_communities, + remove::remove_community, + update::update_community, + }, + custom_emoji::{ + create::create_custom_emoji, + delete::delete_custom_emoji, + update::update_custom_emoji, + }, + post::{ + create::create_post, + delete::delete_post, + read::get_post, + remove::remove_post, + update::update_post, + }, + private_message::{ + create::create_private_message, + delete::delete_private_message, + read::get_private_message, + update::update_private_message, + }, site::{create::create_site, read::get_site, update::update_site}, - PerformCrud, + user::{create::register, delete::delete_account}, }; use lemmy_apub::{ api::{ @@ -137,29 +141,23 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::resource("/community") .guard(guard::Post()) .wrap(rate_limit.register()) - .route(web::post().to(route_post_crud::)), + .route(web::post().to(create_community)), ) .service( web::scope("/community") .wrap(rate_limit.message()) .route("", web::get().to(get_community)) - .route("", web::put().to(route_post_crud::)) - .route("/hide", web::put().to(route_post::)) + .route("", web::put().to(update_community)) + .route("/hide", web::put().to(hide_community)) .route("/list", web::get().to(list_communities)) .route("/follow", web::post().to(follow_community)) - .route("/block", web::post().to(route_post::)) - .route( - "/delete", - web::post().to(route_post_crud::), - ) + .route("/block", web::post().to(block_community)) + .route("/delete", web::post().to(delete_community)) // Mod Actions - .route( - "/remove", - web::post().to(route_post_crud::), - ) + .route("/remove", web::post().to(remove_community)) .route("/transfer", web::post().to(route_post::)) - .route("/ban_user", web::post().to(route_post::)) - .route("/mod", web::post().to(route_post::)), + .route("/ban_user", web::post().to(ban_from_community)) + .route("/mod", web::post().to(add_mod_to_community)), ) .service( web::scope("/federated_instances") @@ -179,18 +177,18 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .wrap(rate_limit.message()) .route("", web::get().to(get_post)) .route("", web::put().to(update_post)) - .route("/delete", web::post().to(route_post_crud::)) - .route("/remove", web::post().to(route_post_crud::)) + .route("/delete", web::post().to(delete_post)) + .route("/remove", web::post().to(remove_post)) .route( "/mark_as_read", web::post().to(route_post::), ) - .route("/lock", web::post().to(route_post::)) - .route("/feature", web::post().to(route_post::)) + .route("/lock", web::post().to(lock_post)) + .route("/feature", web::post().to(feature_post)) .route("/list", web::get().to(list_posts)) .route("/like", web::post().to(like_post)) .route("/save", web::put().to(route_post::)) - .route("/report", web::post().to(route_post::)) + .route("/report", web::post().to(create_post_report)) .route( "/report/resolve", web::put().to(route_post::), @@ -221,7 +219,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("/like", web::post().to(like_comment)) .route("/save", web::put().to(save_comment)) .route("/list", web::get().to(list_comments)) - .route("/report", web::post().to(route_post::)) + .route("/report", web::post().to(create_comment_report)) .route("/report/resolve", web::put().to(resolve_comment_report)) .route("/report/list", web::get().to(list_comment_reports)), ) @@ -230,12 +228,9 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::scope("/private_message") .wrap(rate_limit.message()) .route("/list", web::get().to(get_private_message)) - .route("", web::post().to(route_post_crud::)) - .route("", web::put().to(route_post_crud::)) - .route( - "/delete", - web::post().to(route_post_crud::), - ) + .route("", web::post().to(create_private_message)) + .route("", web::put().to(update_private_message)) + .route("/delete", web::post().to(delete_private_message)) .route( "/mark_as_read", web::post().to(route_post::), @@ -260,7 +255,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::resource("/user/register") .guard(guard::Post()) .wrap(rate_limit.register()) - .route(web::post().to(route_post_crud::)), + .route(web::post().to(register)), ) .service( // Handle captcha separately @@ -280,15 +275,12 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { ) .route("/replies", web::get().to(route_get::)) // Admin action. I don't like that it's in /user - .route("/ban", web::post().to(route_post::)) + .route("/ban", web::post().to(ban_from_site)) .route("/banned", web::get().to(route_get::)) .route("/block", web::post().to(route_post::)) // Account actions. I don't like that they're in /user maybe /accounts .route("/login", web::post().to(route_post::)) - .route( - "/delete_account", - web::post().to(route_post_crud::), - ) + .route("/delete_account", web::post().to(delete_account)) .route( "/password_reset", web::post().to(route_post::), @@ -343,12 +335,9 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/custom_emoji") .wrap(rate_limit.message()) - .route("", web::post().to(route_post_crud::)) - .route("", web::put().to(route_post_crud::)) - .route( - "/delete", - web::post().to(route_post_crud::), - ), + .route("", web::post().to(create_custom_emoji)) + .route("", web::put().to(update_custom_emoji)) + .route("/delete", web::post().to(delete_custom_emoji)), ), ); } @@ -408,43 +397,3 @@ where { perform::(data.0, context, apub_data).await } - -async fn perform_crud<'a, Data>( - data: Data, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: PerformCrud - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - let res = data.perform(&context).await?; - let res_clone = res.clone(); - let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await }; - if *SYNCHRONOUS_FEDERATION { - fed_task.await?; - } else { - spawn_try_task(fed_task); - } - Ok(HttpResponse::Ok().json(&res)) -} - -async fn route_post_crud<'a, Data>( - data: web::Json, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: PerformCrud - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - perform_crud::(data.0, context, apub_data).await -} From 2d0f77af590de70d228a1bdbaab0c937e596c090 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 2 Aug 2023 19:02:53 +0200 Subject: [PATCH 11/11] Dont use sha hash for password reset token (fixes #3491) (#3795) --- Cargo.lock | 2 -- Cargo.toml | 1 - crates/api_common/src/utils.rs | 3 +- crates/apub/Cargo.toml | 1 - crates/db_schema/Cargo.toml | 2 -- .../src/impls/password_reset_request.rs | 36 ++++--------------- crates/db_schema/src/schema.rs | 2 +- .../src/source/password_reset_request.rs | 4 +-- .../down.sql | 1 + .../up.sql | 1 + 10 files changed, 13 insertions(+), 40 deletions(-) create mode 100644 migrations/2023-08-02-144930_password-reset-token/down.sql create mode 100644 migrations/2023-08-02-144930_password-reset-token/up.sql diff --git a/Cargo.lock b/Cargo.lock index bac96d5ed..98a890959 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2678,7 +2678,6 @@ dependencies = [ "serde_json", "serde_with", "serial_test", - "sha2", "strum_macros", "task-local-extensions", "tokio", @@ -2711,7 +2710,6 @@ dependencies = [ "serde_json", "serde_with", "serial_test", - "sha2", "strum", "strum_macros", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 405ed9d4e..424c10e73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,6 @@ diesel_ltree = "0.3.0" typed-builder = "0.15.0" serial_test = "2.0.0" tokio = { version = "1.29.1", features = ["full"] } -sha2 = "0.10.7" regex = "1.9.0" once_cell = "1.18.0" diesel-derive-newtype = "2.1.0" diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 5a678191b..6bdc30285 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -342,9 +342,8 @@ pub async fn send_password_reset_email( let token = uuid::Uuid::new_v4().to_string(); // Insert the row - let token2 = token.clone(); let local_user_id = user.local_user.id; - PasswordResetRequest::create_token(pool, local_user_id, &token2).await?; + PasswordResetRequest::create_token(pool, local_user_id, token.clone()).await?; let email = &user.local_user.email.clone().expect("email"); let lang = get_interface_language(user); diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index cdddea4fc..ebdf3245e 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -33,7 +33,6 @@ http = { workspace = true } futures = { workspace = true } itertools = { workspace = true } uuid = { workspace = true } -sha2 = { workspace = true } async-trait = { workspace = true } anyhow = { workspace = true } reqwest = { workspace = true } diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index a5d3e21f5..3370a5594 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -22,7 +22,6 @@ full = [ "bcrypt", "lemmy_utils", "activitypub_federation", - "sha2", "regex", "once_cell", "serde_json", @@ -60,7 +59,6 @@ diesel-async = { workspace = true, features = [ "postgres", "deadpool", ], optional = true } -sha2 = { workspace = true, optional = true } regex = { workspace = true, optional = true } once_cell = { workspace = true, optional = true } diesel_ltree = { workspace = true, optional = true } diff --git a/crates/db_schema/src/impls/password_reset_request.rs b/crates/db_schema/src/impls/password_reset_request.rs index 9daaa1664..a5a8fc494 100644 --- a/crates/db_schema/src/impls/password_reset_request.rs +++ b/crates/db_schema/src/impls/password_reset_request.rs @@ -1,11 +1,6 @@ use crate::{ newtypes::LocalUserId, - schema::password_reset_request::dsl::{ - local_user_id, - password_reset_request, - published, - token_encrypted, - }, + schema::password_reset_request::dsl::{local_user_id, password_reset_request, published, token}, source::password_reset_request::{PasswordResetRequest, PasswordResetRequestForm}, traits::Crud, utils::{get_conn, DbPool}, @@ -17,7 +12,6 @@ use diesel::{ QueryDsl, }; use diesel_async::RunQueryDsl; -use sha2::{Digest, Sha256}; #[async_trait] impl Crud for PasswordResetRequest { @@ -49,29 +43,22 @@ impl PasswordResetRequest { pub async fn create_token( pool: &mut DbPool<'_>, from_local_user_id: LocalUserId, - token: &str, + token_: String, ) -> Result { - let mut hasher = Sha256::new(); - hasher.update(token); - let token_hash: String = bytes_to_hex(hasher.finalize().to_vec()); - let form = PasswordResetRequestForm { local_user_id: from_local_user_id, - token_encrypted: token_hash, + token: token_, }; Self::create(pool, &form).await } pub async fn read_from_token( pool: &mut DbPool<'_>, - token: &str, + token_: &str, ) -> Result { let conn = &mut get_conn(pool).await?; - let mut hasher = Sha256::new(); - hasher.update(token); - let token_hash: String = bytes_to_hex(hasher.finalize().to_vec()); password_reset_request - .filter(token_encrypted.eq(token_hash)) + .filter(token.eq(token_)) .filter(published.gt(now - 1.days())) .first::(conn) .await @@ -91,14 +78,6 @@ impl PasswordResetRequest { } } -fn bytes_to_hex(bytes: Vec) -> String { - let mut str = String::new(); - for byte in bytes { - str = format!("{str}{byte:02x}"); - } - str -} - #[cfg(test)] mod tests { #![allow(clippy::unwrap_used)] @@ -142,17 +121,16 @@ mod tests { let inserted_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); let token = "nope"; - let token_encrypted_ = "ca3704aa0b06f5954c79ee837faa152d84d6b2d42838f0637a15eda8337dbdce"; let inserted_password_reset_request = - PasswordResetRequest::create_token(pool, inserted_local_user.id, token) + PasswordResetRequest::create_token(pool, inserted_local_user.id, token.to_string()) .await .unwrap(); let expected_password_reset_request = PasswordResetRequest { id: inserted_password_reset_request.id, local_user_id: inserted_local_user.id, - token_encrypted: token_encrypted_.to_string(), + token: token.to_string(), published: inserted_password_reset_request.published, }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index d6e2cf69c..7106b1c90 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -535,7 +535,7 @@ diesel::table! { diesel::table! { password_reset_request (id) { id -> Int4, - token_encrypted -> Text, + token -> Text, published -> Timestamp, local_user_id -> Int4, } diff --git a/crates/db_schema/src/source/password_reset_request.rs b/crates/db_schema/src/source/password_reset_request.rs index 6c28c649a..6e1b572d3 100644 --- a/crates/db_schema/src/source/password_reset_request.rs +++ b/crates/db_schema/src/source/password_reset_request.rs @@ -7,7 +7,7 @@ use crate::schema::password_reset_request; #[cfg_attr(feature = "full", diesel(table_name = password_reset_request))] pub struct PasswordResetRequest { pub id: i32, - pub token_encrypted: String, + pub token: String, pub published: chrono::NaiveDateTime, pub local_user_id: LocalUserId, } @@ -16,5 +16,5 @@ pub struct PasswordResetRequest { #[cfg_attr(feature = "full", diesel(table_name = password_reset_request))] pub struct PasswordResetRequestForm { pub local_user_id: LocalUserId, - pub token_encrypted: String, + pub token: String, } diff --git a/migrations/2023-08-02-144930_password-reset-token/down.sql b/migrations/2023-08-02-144930_password-reset-token/down.sql new file mode 100644 index 000000000..5f938da24 --- /dev/null +++ b/migrations/2023-08-02-144930_password-reset-token/down.sql @@ -0,0 +1 @@ +alter table password_reset_request rename column token to token_encrypted; diff --git a/migrations/2023-08-02-144930_password-reset-token/up.sql b/migrations/2023-08-02-144930_password-reset-token/up.sql new file mode 100644 index 000000000..0bdd1655b --- /dev/null +++ b/migrations/2023-08-02-144930_password-reset-token/up.sql @@ -0,0 +1 @@ +alter table password_reset_request rename column token_encrypted to token;