From 63a2f7b7e3bec6d6849a597b67fdaf05e0bf623d Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 11:17:50 +0200 Subject: [PATCH 1/7] Drop timestamp column from votes (ref #5016) --- crates/db_schema/src/impls/comment.rs | 1 - crates/db_schema/src/impls/post.rs | 1 - crates/db_schema/src/schema.rs | 2 -- crates/db_schema/src/source/comment.rs | 1 - crates/db_schema/src/source/post.rs | 1 - crates/db_views/src/post_view.rs | 1 - migrations/2024-10-17-091053_vote-no-timestamp/down.sql | 2 ++ migrations/2024-10-17-091053_vote-no-timestamp/up.sql | 2 ++ 8 files changed, 4 insertions(+), 7 deletions(-) create mode 100644 migrations/2024-10-17-091053_vote-no-timestamp/down.sql create mode 100644 migrations/2024-10-17-091053_vote-no-timestamp/up.sql diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index ec246c1215..737486d92f 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -300,7 +300,6 @@ mod tests { comment_id: inserted_comment.id, post_id: inserted_post.id, person_id: inserted_person.id, - published: inserted_comment_like.published, score: 1, }; diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index fb62455853..0a0b34db8e 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -500,7 +500,6 @@ mod tests { let expected_post_like = PostLike { post_id: inserted_post.id, person_id: inserted_person.id, - published: inserted_post_like.published, score: 1, }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 5534c4f608..c89b1931ec 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -125,7 +125,6 @@ diesel::table! { comment_id -> Int4, post_id -> Int4, score -> Int2, - published -> Timestamptz, } } @@ -816,7 +815,6 @@ diesel::table! { post_id -> Int4, person_id -> Int4, score -> Int2, - published -> Timestamptz, } } diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index e7d031c682..b7b4304fac 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -104,7 +104,6 @@ pub struct CommentLike { pub comment_id: CommentId, pub post_id: PostId, // TODO this is redundant pub score: i16, - pub published: DateTime, } #[derive(Clone)] diff --git a/crates/db_schema/src/source/post.rs b/crates/db_schema/src/source/post.rs index 3819bd773a..e1de250c63 100644 --- a/crates/db_schema/src/source/post.rs +++ b/crates/db_schema/src/source/post.rs @@ -150,7 +150,6 @@ pub struct PostLike { pub post_id: PostId, pub person_id: PersonId, pub score: i16, - pub published: DateTime, } #[derive(Clone)] diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index e07133471b..d05d668c20 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -1125,7 +1125,6 @@ mod tests { let expected_post_like = PostLike { post_id: data.inserted_post.id, person_id: data.local_user_view.person.id, - published: inserted_post_like.published, score: 1, }; assert_eq!(expected_post_like, inserted_post_like); diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql new file mode 100644 index 0000000000..295dafc42b --- /dev/null +++ b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql @@ -0,0 +1,2 @@ +alter table post_like add column published timestamptz not null default now(); +alter table comment_like add column published timestamptz not null default now(); \ No newline at end of file diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql new file mode 100644 index 0000000000..0b4107735c --- /dev/null +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -0,0 +1,2 @@ +alter table post_like drop published; +alter table comment_like drop published; \ No newline at end of file From a28d45d2424074c1f232d90ab904d792cc46c888 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 11:23:16 +0200 Subject: [PATCH 2/7] fmt --- migrations/2024-10-17-091053_vote-no-timestamp/down.sql | 8 ++++++-- migrations/2024-10-17-091053_vote-no-timestamp/up.sql | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql index 295dafc42b..ec51c3afa2 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql @@ -1,2 +1,6 @@ -alter table post_like add column published timestamptz not null default now(); -alter table comment_like add column published timestamptz not null default now(); \ No newline at end of file +ALTER TABLE post_like + ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + +ALTER TABLE comment_like + ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql index 0b4107735c..78d1d698a3 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -1,2 +1,6 @@ -alter table post_like drop published; -alter table comment_like drop published; \ No newline at end of file +ALTER TABLE post_like + DROP published; + +ALTER TABLE comment_like + DROP published; + From 1a0770a0ef2f10a1ff7d842620b3d53da831d6ce Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 11:45:58 +0200 Subject: [PATCH 3/7] Also remove comment_like.post_id --- crates/api/src/comment/like.rs | 1 - crates/api_crud/src/comment/create.rs | 1 - crates/apub/src/activities/create_or_update/comment.rs | 1 - crates/apub/src/activities/voting/mod.rs | 1 - crates/db_schema/src/aggregates/comment_aggregates.rs | 2 -- crates/db_schema/src/aggregates/person_aggregates.rs | 2 -- crates/db_schema/src/impls/comment.rs | 2 -- crates/db_schema/src/schema.rs | 2 -- crates/db_schema/src/source/comment.rs | 2 -- crates/db_views/src/comment_view.rs | 2 -- crates/db_views/src/vote_view.rs | 7 +++---- migrations/2024-10-17-091053_vote-no-timestamp/down.sql | 4 ++-- migrations/2024-10-17-091053_vote-no-timestamp/up.sql | 3 ++- 13 files changed, 7 insertions(+), 23 deletions(-) diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index 749b90426e..e93b8513fe 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -67,7 +67,6 @@ pub async fn like_comment( 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, }; diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index f85a4d9290..2f67fa7e7e 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -132,7 +132,6 @@ pub async fn create_comment( // You like your own comment by default let like_form = CommentLikeForm { comment_id: inserted_comment.id, - post_id: post.id, person_id: local_user_view.person.id, score: 1, }; diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index b2c4360492..0a07371516 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -153,7 +153,6 @@ impl ActivityHandler for CreateOrUpdateNote { // author likes their own comment by default let like_form = CommentLikeForm { comment_id: comment.id, - post_id: comment.post_id, person_id: comment.creator_id, score: 1, }; diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 3e59cb7d0c..7c39b2246d 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -62,7 +62,6 @@ async fn vote_comment( let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, - post_id: comment.post_id, person_id: actor.id, score: vote_type.into(), }; diff --git a/crates/db_schema/src/aggregates/comment_aggregates.rs b/crates/db_schema/src/aggregates/comment_aggregates.rs index fc825ec99e..a97bb565b8 100644 --- a/crates/db_schema/src/aggregates/comment_aggregates.rs +++ b/crates/db_schema/src/aggregates/comment_aggregates.rs @@ -96,7 +96,6 @@ mod tests { let comment_like = CommentLikeForm { comment_id: inserted_comment.id, - post_id: inserted_post.id, person_id: inserted_person.id, score: 1, }; @@ -112,7 +111,6 @@ mod tests { // Add a post dislike from the other person let comment_dislike = CommentLikeForm { comment_id: inserted_comment.id, - post_id: inserted_post.id, person_id: another_inserted_person.id, score: -1, }; diff --git a/crates/db_schema/src/aggregates/person_aggregates.rs b/crates/db_schema/src/aggregates/person_aggregates.rs index c68c90b0d0..6e0eacc078 100644 --- a/crates/db_schema/src/aggregates/person_aggregates.rs +++ b/crates/db_schema/src/aggregates/person_aggregates.rs @@ -82,7 +82,6 @@ mod tests { let mut comment_like = CommentLikeForm { comment_id: inserted_comment.id, person_id: inserted_person.id, - post_id: inserted_post.id, score: 1, }; @@ -99,7 +98,6 @@ mod tests { let child_comment_like = CommentLikeForm { comment_id: inserted_child_comment.id, person_id: another_inserted_person.id, - post_id: inserted_post.id, score: 1, }; diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index 737486d92f..e1d48d5785 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -289,7 +289,6 @@ mod tests { // Comment Like let comment_like_form = CommentLikeForm { comment_id: inserted_comment.id, - post_id: inserted_post.id, person_id: inserted_person.id, score: 1, }; @@ -298,7 +297,6 @@ mod tests { let expected_comment_like = CommentLike { comment_id: inserted_comment.id, - post_id: inserted_post.id, person_id: inserted_person.id, score: 1, }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index c89b1931ec..af7209edd5 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -123,7 +123,6 @@ diesel::table! { comment_like (person_id, comment_id) { person_id -> Int4, comment_id -> Int4, - post_id -> Int4, score -> Int2, } } @@ -997,7 +996,6 @@ diesel::joinable!(comment -> post (post_id)); diesel::joinable!(comment_aggregates -> comment (comment_id)); diesel::joinable!(comment_like -> comment (comment_id)); diesel::joinable!(comment_like -> person (person_id)); -diesel::joinable!(comment_like -> post (post_id)); diesel::joinable!(comment_reply -> comment (comment_id)); diesel::joinable!(comment_reply -> person (recipient_id)); diesel::joinable!(comment_report -> comment (comment_id)); diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index b7b4304fac..51e12c45e9 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -102,7 +102,6 @@ pub struct CommentUpdateForm { pub struct CommentLike { pub person_id: PersonId, pub comment_id: CommentId, - pub post_id: PostId, // TODO this is redundant pub score: i16, } @@ -112,7 +111,6 @@ pub struct CommentLike { pub struct CommentLikeForm { pub person_id: PersonId, pub comment_id: CommentId, - pub post_id: PostId, // TODO this is redundant pub score: i16, } diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index dc9aceec0e..55fea4d66b 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -601,7 +601,6 @@ mod tests { let comment_like_form = CommentLikeForm { comment_id: inserted_comment_0.id, - post_id: inserted_post.id, person_id: inserted_timmy_person.id, score: 1, }; @@ -701,7 +700,6 @@ mod tests { // Like a new comment let comment_like_form = CommentLikeForm { comment_id: data.inserted_comment_1.id, - post_id: data.inserted_post.id, person_id: data.timmy_local_user_view.person.id, score: 1, }; diff --git a/crates/db_views/src/vote_view.rs b/crates/db_views/src/vote_view.rs index 9c5fef8551..0fd64decad 100644 --- a/crates/db_views/src/vote_view.rs +++ b/crates/db_views/src/vote_view.rs @@ -10,7 +10,7 @@ use diesel::{ use diesel_async::RunQueryDsl; use lemmy_db_schema::{ newtypes::{CommentId, PostId}, - schema::{comment_like, community_person_ban, person, post, post_like}, + schema::{comment, comment_like, community_person_ban, person, post, post_like}, utils::{get_conn, limit_and_offset, DbPool}, }; @@ -59,7 +59,8 @@ impl VoteView { comment_like::table .inner_join(person::table) - .inner_join(post::table) + .inner_join(comment::table) + .inner_join(post::table.on(comment::post_id.eq(post::id))) // Join to community_person_ban to get creator_banned_from_community .left_join( community_person_ban::table.on( @@ -173,7 +174,6 @@ mod tests { // Timothy votes down his own comment let timmy_comment_vote_form = CommentLikeForm { - post_id: inserted_post.id, comment_id: inserted_comment.id, person_id: inserted_timmy.id, score: -1, @@ -182,7 +182,6 @@ mod tests { // Sara upvotes timmy's comment let sara_comment_vote_form = CommentLikeForm { - post_id: inserted_post.id, comment_id: inserted_comment.id, person_id: inserted_sara.id, score: 1, diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql index ec51c3afa2..0b2639913f 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql @@ -1,6 +1,6 @@ ALTER TABLE post_like ADD COLUMN published timestamptz NOT NULL DEFAULT now(); - ALTER TABLE comment_like ADD COLUMN published timestamptz NOT NULL DEFAULT now(); - +ALTER TABLE comment_like + ADD COLUMN post_id int NOT NULL; diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql index 78d1d698a3..46dc485923 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -1,6 +1,7 @@ ALTER TABLE post_like DROP published; - ALTER TABLE comment_like DROP published; +ALTER TABLE comment_like + DROP post_id; From 719efb28bc35405a991bcba46a7b22929d7d514d Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 12:06:55 +0200 Subject: [PATCH 4/7] restore value of comment_like.post_id --- api_tests/prepare-drone-federation-test.sh | 2 +- api_tests/run-federation-test.sh | 2 +- .../down.sql | 19 ++++++++++++++++++- .../up.sql | 2 ++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index 65c4827d9f..b17e2017e7 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -23,7 +23,7 @@ fi --danger-dummy-mode \ --api-key "my-pictrs-key" \ filesystem -p /tmp/pictrs/files \ - sled -p /tmp/pictrs/sled-repo 2>&1 & + sled -p /tmp/pictrs/sled-repo & for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE" diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index 969a95b3e7..f9eab50395 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -11,7 +11,7 @@ killall -s1 lemmy_server || true popd pnpm i -pnpm api-test || true +pnpm api-test-image || true killall -s1 lemmy_server || true killall -s1 pict-rs || true diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql index 0b2639913f..928530641c 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql @@ -1,6 +1,23 @@ ALTER TABLE post_like ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + ALTER TABLE comment_like ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + ALTER TABLE comment_like - ADD COLUMN post_id int NOT NULL; + ADD COLUMN post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE; + +UPDATE + comment_like +SET + post_id = ( + SELECT + post_id + FROM + comment + WHERE + comment.id = comment_like.comment_id); + +ALTER TABLE comment_like + ALTER COLUMN post_id SET NOT NULL; + diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql index 46dc485923..f094bdf5a4 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -1,7 +1,9 @@ ALTER TABLE post_like DROP published; + ALTER TABLE comment_like DROP published; + ALTER TABLE comment_like DROP post_id; From 019bf67de012d6daca05a56d7f62cb0f1508dded Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 14:22:36 +0200 Subject: [PATCH 5/7] set columns null before dropping --- .../up.sql | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql index f094bdf5a4..2cf906a09f 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -1,3 +1,30 @@ +-- set all column values to null to reclaim disk space +-- https://dba.stackexchange.com/a/117513 +ALTER TABLE post_like + ALTER COLUMN published DROP NOT NULL; + +UPDATE + post_like +SET + published = NULL; + +ALTER TABLE comment_like + ALTER COLUMN published DROP NOT NULL; + +UPDATE + comment_like +SET + published = NULL; + +ALTER TABLE comment_like + ALTER COLUMN post_id DROP NOT NULL; + +UPDATE + post_like +SET + post_id = NULL; + +-- drop the columns ALTER TABLE post_like DROP published; From 08055b9dfb3b11a4eaee304eab75f9bb3c5862fe Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 14:47:38 +0200 Subject: [PATCH 6/7] clean --- api_tests/prepare-drone-federation-test.sh | 2 +- api_tests/run-federation-test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index b17e2017e7..65c4827d9f 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -23,7 +23,7 @@ fi --danger-dummy-mode \ --api-key "my-pictrs-key" \ filesystem -p /tmp/pictrs/files \ - sled -p /tmp/pictrs/sled-repo & + sled -p /tmp/pictrs/sled-repo 2>&1 & for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE" diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index f9eab50395..969a95b3e7 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -11,7 +11,7 @@ killall -s1 lemmy_server || true popd pnpm i -pnpm api-test-image || true +pnpm api-test || true killall -s1 lemmy_server || true killall -s1 pict-rs || true From fd8a6b46f7ac70345a443f01409c4b1d3a62f161 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 17 Oct 2024 15:08:56 +0200 Subject: [PATCH 7/7] add setting store_vote_timestamps --- config/defaults.hjson | 3 ++ crates/api/src/comment/like.rs | 26 +++++----- crates/api/src/post/like.rs | 22 ++++----- crates/api_crud/src/comment/create.rs | 20 ++++---- crates/api_crud/src/post/create.rs | 18 +++---- .../activities/create_or_update/comment.rs | 16 +++--- .../src/activities/create_or_update/post.rs | 16 +++--- crates/apub/src/activities/voting/mod.rs | 40 +++++++-------- .../src/aggregates/comment_aggregates.rs | 27 +++++----- .../src/aggregates/person_aggregates.rs | 46 +++++++++-------- .../src/aggregates/post_aggregates.rs | 27 +++++----- crates/db_schema/src/impls/comment.rs | 45 +++++++++++------ crates/db_schema/src/impls/post.rs | 49 ++++++++++--------- crates/db_schema/src/schema.rs | 2 + crates/db_schema/src/source/comment.rs | 4 +- crates/db_schema/src/source/post.rs | 4 +- crates/db_schema/src/traits.rs | 10 +++- crates/db_views/src/comment_view.rs | 34 +++++++------ crates/db_views/src/post_view.rs | 49 +++++++++++-------- crates/db_views/src/structs.rs | 2 + crates/db_views/src/vote_view.rs | 41 ++++++---------- crates/utils/src/settings/structs.rs | 5 ++ .../down.sql | 12 ++++- .../up.sql | 23 +++------ 24 files changed, 285 insertions(+), 256 deletions(-) diff --git a/config/defaults.hjson b/config/defaults.hjson index f0b9d56df5..6107589b46 100644 --- a/config/defaults.hjson +++ b/config/defaults.hjson @@ -35,6 +35,9 @@ database: "string" # Maximum number of active sql connections pool_size: 30 + # Set true to store the time when votes were cast. Requires more storage space but can be + # used to detect vote manipulation. + store_vote_timestamps: false } # Pictrs image server configuration. pictrs: { diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index e93b8513fe..0ed2edc2ab 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -9,11 +9,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ newtypes::LocalUserId, - source::{ - comment::{CommentLike, CommentLikeForm}, - comment_reply::CommentReply, - local_site::LocalSite, - }, + source::{comment::CommentLike, comment_reply::CommentReply, local_site::LocalSite}, traits::Likeable, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; @@ -65,23 +61,23 @@ pub async fn like_comment( } } - let like_form = CommentLikeForm { - comment_id: data.comment_id, - person_id: local_user_view.person.id, - score: data.score, - }; - // Remove any likes first let person_id = local_user_view.person.id; 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); + let do_add = data.score != 0 && (data.score == 1 || data.score == -1); if do_add { - CommentLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; + CommentLike::like( + &mut context.pool(), + person_id, + data.comment_id, + data.score, + context.settings(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; } ActivityChannel::submit_activity( diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index c81d9630a2..0aef100348 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -17,7 +17,7 @@ use lemmy_db_schema::{ source::{ community::Community, local_site::LocalSite, - post::{Post, PostLike, PostLikeForm}, + post::{Post, PostLike}, }, traits::{Crud, Likeable}, }; @@ -54,23 +54,23 @@ pub async fn like_post( ) .await?; - 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; 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); + let do_add = data.score != 0 && (data.score == 1 || data.score == -1); if do_add { - PostLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; + PostLike::like( + &mut context.pool(), + person_id, + post_id, + data.score, + context.settings(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; } mark_post_as_read(person_id, post_id, &mut context.pool()).await?; diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 2f67fa7e7e..88fae7140a 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -19,7 +19,7 @@ use lemmy_db_schema::{ impls::actor_language::default_post_language, source::{ actor_language::CommunityLanguage, - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentInsertForm, CommentLike}, comment_reply::{CommentReply, CommentReplyUpdateForm}, local_site::LocalSite, person_mention::{PersonMention, PersonMentionUpdateForm}, @@ -130,15 +130,15 @@ pub async fn create_comment( .await?; // You like your own comment by default - let like_form = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: local_user_view.person.id, - score: 1, - }; - - CommentLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; + CommentLike::like( + &mut context.pool(), + local_user_view.person.id, + inserted_comment.id, + 1, + context.settings(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; ActivityChannel::submit_activity( SendActivityData::CreateComment(inserted_comment.clone()), diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 90c68bdbd9..8a8b05b59a 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -22,7 +22,7 @@ use lemmy_db_schema::{ actor_language::CommunityLanguage, community::Community, local_site::LocalSite, - post::{Post, PostInsertForm, PostLike, PostLikeForm}, + post::{Post, PostInsertForm, PostLike}, }, traits::{Crud, Likeable}, utils::diesel_url_create, @@ -159,15 +159,15 @@ pub async fn create_post( // They like their own post by default let person_id = local_user_view.person.id; let post_id = inserted_post.id; - let like_form = PostLikeForm { - post_id, + PostLike::like( + &mut context.pool(), person_id, - score: 1, - }; - - PostLike::like(&mut context.pool(), &like_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; + post_id, + 1, + context.settings(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikePost)?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?; diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 0a07371516..b2a8272e4a 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -32,7 +32,7 @@ use lemmy_db_schema::{ newtypes::PersonId, source::{ activity::ActivitySendTargets, - comment::{Comment, CommentLike, CommentLikeForm}, + comment::{Comment, CommentLike}, community::Community, person::Person, post::Post, @@ -151,12 +151,14 @@ impl ActivityHandler for CreateOrUpdateNote { let comment = ApubComment::from_json(self.object, context).await?; // author likes their own comment by default - let like_form = CommentLikeForm { - comment_id: comment.id, - person_id: comment.creator_id, - score: 1, - }; - CommentLike::like(&mut context.pool(), &like_form).await?; + CommentLike::like( + &mut context.pool(), + comment.creator_id, + comment.id, + 1, + context.settings(), + ) + .await?; // Calculate initial hot_rank CommentAggregates::update_hot_rank(&mut context.pool(), comment.id).await?; diff --git a/crates/apub/src/activities/create_or_update/post.rs b/crates/apub/src/activities/create_or_update/post.rs index fb53100f60..b18b77f968 100644 --- a/crates/apub/src/activities/create_or_update/post.rs +++ b/crates/apub/src/activities/create_or_update/post.rs @@ -28,7 +28,7 @@ use lemmy_db_schema::{ activity::ActivitySendTargets, community::Community, person::Person, - post::{Post, PostLike, PostLikeForm}, + post::{Post, PostLike}, }, traits::{Crud, Likeable}, }; @@ -118,12 +118,14 @@ impl ActivityHandler for CreateOrUpdatePage { let post = ApubPost::from_json(self.object, context).await?; // author likes their own post by default - let like_form = PostLikeForm { - post_id: post.id, - person_id: post.creator_id, - score: 1, - }; - PostLike::like(&mut context.pool(), &like_form).await?; + PostLike::like( + &mut context.pool(), + post.creator_id, + post.id, + 1, + context.settings(), + ) + .await?; // Calculate initial hot_rank for post PostAggregates::update_ranks(&mut context.pool(), post.id).await?; diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 7c39b2246d..12fe28e2cb 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -14,10 +14,10 @@ use lemmy_db_schema::{ newtypes::DbUrl, source::{ activity::ActivitySendTargets, - comment::{CommentLike, CommentLikeForm}, + comment::CommentLike, community::Community, person::Person, - post::{PostLike, PostLikeForm}, + post::PostLike, }, traits::Likeable, }; @@ -59,15 +59,15 @@ async fn vote_comment( comment: &ApubComment, context: &Data, ) -> LemmyResult<()> { - let comment_id = comment.id; - let like_form = CommentLikeForm { - comment_id, - person_id: actor.id, - score: vote_type.into(), - }; - let person_id = actor.id; - CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; - CommentLike::like(&mut context.pool(), &like_form).await?; + CommentLike::remove(&mut context.pool(), actor.id, comment.id).await?; + CommentLike::like( + &mut context.pool(), + actor.id, + comment.id, + vote_type.into(), + context.settings(), + ) + .await?; Ok(()) } @@ -78,15 +78,15 @@ async fn vote_post( post: &ApubPost, context: &Data, ) -> LemmyResult<()> { - let post_id = post.id; - let like_form = PostLikeForm { - post_id: post.id, - person_id: actor.id, - score: vote_type.into(), - }; - let person_id = actor.id; - PostLike::remove(&mut context.pool(), person_id, post_id).await?; - PostLike::like(&mut context.pool(), &like_form).await?; + PostLike::remove(&mut context.pool(), actor.id, post.id).await?; + PostLike::like( + &mut context.pool(), + actor.id, + post.id, + vote_type.into(), + context.settings(), + ) + .await?; Ok(()) } diff --git a/crates/db_schema/src/aggregates/comment_aggregates.rs b/crates/db_schema/src/aggregates/comment_aggregates.rs index a97bb565b8..01e479d4c5 100644 --- a/crates/db_schema/src/aggregates/comment_aggregates.rs +++ b/crates/db_schema/src/aggregates/comment_aggregates.rs @@ -35,7 +35,7 @@ mod tests { use crate::{ aggregates::comment_aggregates::CommentAggregates, source::{ - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentInsertForm, CommentLike}, community::{Community, CommunityInsertForm}, instance::Instance, person::{Person, PersonInsertForm}, @@ -45,6 +45,7 @@ mod tests { utils::build_db_pool_for_tests, }; use diesel::result::Error; + use lemmy_utils::settings::structs::Settings; use pretty_assertions::assert_eq; use serial_test::serial; @@ -94,13 +95,8 @@ mod tests { let _inserted_child_comment = Comment::create(pool, &child_comment_form, Some(&inserted_comment.path)).await?; - let comment_like = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: inserted_person.id, - score: 1, - }; - - CommentLike::like(pool, &comment_like).await?; + let settings = Settings::default(); + CommentLike::like(pool, inserted_person.id, inserted_comment.id, 1, &settings).await?; let comment_aggs_before_delete = CommentAggregates::read(pool, inserted_comment.id).await?; @@ -109,13 +105,14 @@ mod tests { assert_eq!(0, comment_aggs_before_delete.downvotes); // Add a post dislike from the other person - let comment_dislike = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: another_inserted_person.id, - score: -1, - }; - - CommentLike::like(pool, &comment_dislike).await?; + CommentLike::like( + pool, + another_inserted_person.id, + inserted_comment.id, + -1, + &settings, + ) + .await?; let comment_aggs_after_dislike = CommentAggregates::read(pool, inserted_comment.id).await?; diff --git a/crates/db_schema/src/aggregates/person_aggregates.rs b/crates/db_schema/src/aggregates/person_aggregates.rs index 6e0eacc078..0a94846137 100644 --- a/crates/db_schema/src/aggregates/person_aggregates.rs +++ b/crates/db_schema/src/aggregates/person_aggregates.rs @@ -20,16 +20,17 @@ mod tests { use crate::{ aggregates::person_aggregates::PersonAggregates, source::{ - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm, CommentUpdateForm}, + comment::{Comment, CommentInsertForm, CommentLike, CommentUpdateForm}, community::{Community, CommunityInsertForm}, instance::Instance, person::{Person, PersonInsertForm}, - post::{Post, PostInsertForm, PostLike, PostLikeForm}, + post::{Post, PostInsertForm, PostLike}, }, traits::{Crud, Likeable}, utils::build_db_pool_for_tests, }; use diesel::result::Error; + use lemmy_utils::settings::structs::Settings; use pretty_assertions::assert_eq; use serial_test::serial; @@ -65,12 +66,8 @@ mod tests { ); let inserted_post = Post::create(pool, &new_post).await?; - let post_like = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_person.id, - score: 1, - }; - let _inserted_post_like = PostLike::like(pool, &post_like).await?; + let settings = Settings::default(); + PostLike::like(pool, inserted_person.id, inserted_post.id, 1, &settings).await?; let comment_form = CommentInsertForm::new( inserted_person.id, @@ -79,13 +76,7 @@ mod tests { ); let inserted_comment = Comment::create(pool, &comment_form, None).await?; - let mut comment_like = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: inserted_person.id, - score: 1, - }; - - let _inserted_comment_like = CommentLike::like(pool, &comment_like).await?; + CommentLike::like(pool, inserted_person.id, inserted_comment.id, 1, &settings).await?; let child_comment_form = CommentInsertForm::new( inserted_person.id, @@ -95,13 +86,14 @@ mod tests { let inserted_child_comment = Comment::create(pool, &child_comment_form, Some(&inserted_comment.path)).await?; - let child_comment_like = CommentLikeForm { - comment_id: inserted_child_comment.id, - person_id: another_inserted_person.id, - score: 1, - }; - - let _inserted_child_comment_like = CommentLike::like(pool, &child_comment_like).await?; + CommentLike::like( + pool, + another_inserted_person.id, + inserted_child_comment.id, + 1, + &settings, + ) + .await?; let person_aggregates_before_delete = PersonAggregates::read(pool, inserted_person.id).await?; @@ -151,8 +143,14 @@ mod tests { let new_parent_comment = Comment::create(pool, &comment_form, None).await?; let _new_child_comment = Comment::create(pool, &child_comment_form, Some(&new_parent_comment.path)).await?; - comment_like.comment_id = new_parent_comment.id; - CommentLike::like(pool, &comment_like).await?; + CommentLike::like( + pool, + inserted_person.id, + new_parent_comment.id, + 1, + &settings, + ) + .await?; let after_comment_add = PersonAggregates::read(pool, inserted_person.id).await?; assert_eq!(2, after_comment_add.comment_count); // TODO: fix person aggregate comment score calculation diff --git a/crates/db_schema/src/aggregates/post_aggregates.rs b/crates/db_schema/src/aggregates/post_aggregates.rs index b63017317b..9b7a041bb4 100644 --- a/crates/db_schema/src/aggregates/post_aggregates.rs +++ b/crates/db_schema/src/aggregates/post_aggregates.rs @@ -58,12 +58,13 @@ mod tests { community::{Community, CommunityInsertForm}, instance::Instance, person::{Person, PersonInsertForm}, - post::{Post, PostInsertForm, PostLike, PostLikeForm}, + post::{Post, PostInsertForm, PostLike}, }, traits::{Crud, Likeable}, utils::build_db_pool_for_tests, }; use diesel::result::Error; + use lemmy_utils::settings::structs::Settings; use pretty_assertions::assert_eq; use serial_test::serial; @@ -113,13 +114,8 @@ mod tests { let inserted_child_comment = Comment::create(pool, &child_comment_form, Some(&inserted_comment.path)).await?; - let post_like = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_person.id, - score: 1, - }; - - PostLike::like(pool, &post_like).await?; + let settings = Settings::default(); + PostLike::like(pool, inserted_person.id, inserted_post.id, 1, &settings).await?; let post_aggs_before_delete = PostAggregates::read(pool, inserted_post.id).await?; @@ -129,13 +125,14 @@ mod tests { assert_eq!(0, post_aggs_before_delete.downvotes); // Add a post dislike from the other person - let post_dislike = PostLikeForm { - post_id: inserted_post.id, - person_id: another_inserted_person.id, - score: -1, - }; - - PostLike::like(pool, &post_dislike).await?; + PostLike::like( + pool, + another_inserted_person.id, + inserted_post.id, + -1, + &settings, + ) + .await?; let post_aggs_after_dislike = PostAggregates::read(pool, inserted_post.id).await?; diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index e1d48d5785..e39eee66be 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -18,6 +18,7 @@ use chrono::{DateTime, Utc}; use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; use diesel_ltree::Ltree; +use lemmy_utils::settings::structs::Settings; use url::Url; impl Comment { @@ -138,16 +139,32 @@ impl Crud for Comment { #[async_trait] impl Likeable for CommentLike { - type Form = CommentLikeForm; type IdType = CommentId; - async fn like(pool: &mut DbPool<'_>, comment_like_form: &CommentLikeForm) -> Result { - use crate::schema::comment_like::dsl::{comment_id, comment_like, person_id}; + async fn like( + pool: &mut DbPool<'_>, + person_id: PersonId, + comment_id: Self::IdType, + score: i16, + settings: &Settings, + ) -> Result { + use crate::schema::comment_like; let conn = &mut get_conn(pool).await?; - insert_into(comment_like) - .values(comment_like_form) - .on_conflict((comment_id, person_id)) + let published = if settings.database.store_vote_timestamps { + Some(Utc::now()) + } else { + None + }; + let form = CommentLikeForm { + person_id, + comment_id, + score, + published, + }; + insert_into(comment_like::table) + .values(&form) + .on_conflict((comment_like::comment_id, comment_like::person_id)) .do_update() - .set(comment_like_form) + .set(&form) .get_result::(conn) .await } @@ -205,7 +222,6 @@ mod tests { Comment, CommentInsertForm, CommentLike, - CommentLikeForm, CommentSaved, CommentSavedForm, CommentUpdateForm, @@ -219,7 +235,7 @@ mod tests { utils::build_db_pool_for_tests, }; use diesel_ltree::Ltree; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use pretty_assertions::assert_eq; use serial_test::serial; use url::Url; @@ -287,18 +303,15 @@ mod tests { Comment::create(pool, &child_comment_form, Some(&inserted_comment.path)).await?; // Comment Like - let comment_like_form = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: inserted_person.id, - score: 1, - }; - - let inserted_comment_like = CommentLike::like(pool, &comment_like_form).await?; + let settings = Settings::default(); + let inserted_comment_like = + CommentLike::like(pool, inserted_person.id, inserted_comment.id, 1, &settings).await?; let expected_comment_like = CommentLike { comment_id: inserted_comment.id, person_id: inserted_person.id, score: 1, + published: None, }; // Comment Saved diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index 0a0b34db8e..4915d387be 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -39,6 +39,7 @@ use diesel::{ TextExpressionMethods, }; use diesel_async::RunQueryDsl; +use lemmy_utils::settings::structs::Settings; use std::collections::HashSet; #[async_trait] @@ -274,15 +275,31 @@ impl Post { #[async_trait] impl Likeable for PostLike { - type Form = PostLikeForm; type IdType = PostId; - async fn like(pool: &mut DbPool<'_>, post_like_form: &PostLikeForm) -> Result { + async fn like( + pool: &mut DbPool<'_>, + person_id: PersonId, + post_id: Self::IdType, + score: i16, + settings: &Settings, + ) -> Result { let conn = &mut get_conn(pool).await?; + let published = if settings.database.store_vote_timestamps { + Some(Utc::now()) + } else { + None + }; + let form = PostLikeForm { + person_id, + post_id, + score, + published, + }; insert_into(post_like::table) - .values(post_like_form) + .values(&form) .on_conflict((post_like::post_id, post_like::person_id)) .do_update() - .set(post_like_form) + .set(&form) .get_result::(conn) .await } @@ -399,22 +416,13 @@ mod tests { community::{Community, CommunityInsertForm}, instance::Instance, person::{Person, PersonInsertForm}, - post::{ - Post, - PostInsertForm, - PostLike, - PostLikeForm, - PostRead, - PostSaved, - PostSavedForm, - PostUpdateForm, - }, + post::{Post, PostInsertForm, PostLike, PostRead, PostSaved, PostSavedForm, PostUpdateForm}, }, traits::{Crud, Likeable, Saveable}, utils::build_db_pool_for_tests, }; use chrono::DateTime; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use pretty_assertions::assert_eq; use serial_test::serial; use std::collections::HashSet; @@ -489,18 +497,15 @@ mod tests { }; // Post Like - let post_like_form = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_person.id, - score: 1, - }; - - let inserted_post_like = PostLike::like(pool, &post_like_form).await?; + let settings = Settings::default(); + let inserted_post_like = + PostLike::like(pool, inserted_person.id, inserted_post.id, 1, &settings).await?; let expected_post_like = PostLike { post_id: inserted_post.id, person_id: inserted_person.id, score: 1, + published: None, }; // Post Save diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index af7209edd5..5ee7d2c427 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -124,6 +124,7 @@ diesel::table! { person_id -> Int4, comment_id -> Int4, score -> Int2, + published -> Nullable, } } @@ -814,6 +815,7 @@ diesel::table! { post_id -> Int4, person_id -> Int4, score -> Int2, + published -> Nullable, } } diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index 51e12c45e9..5a736c63fb 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -103,15 +103,17 @@ pub struct CommentLike { pub person_id: PersonId, pub comment_id: CommentId, pub score: i16, + pub published: Option>, } #[derive(Clone)] #[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] #[cfg_attr(feature = "full", diesel(table_name = comment_like))] -pub struct CommentLikeForm { +pub(crate) struct CommentLikeForm { pub person_id: PersonId, pub comment_id: CommentId, pub score: i16, + pub published: Option>, } #[derive(PartialEq, Eq, Debug)] diff --git a/crates/db_schema/src/source/post.rs b/crates/db_schema/src/source/post.rs index e1de250c63..d418be4598 100644 --- a/crates/db_schema/src/source/post.rs +++ b/crates/db_schema/src/source/post.rs @@ -150,15 +150,17 @@ pub struct PostLike { pub post_id: PostId, pub person_id: PersonId, pub score: i16, + pub published: Option>, } #[derive(Clone)] #[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] #[cfg_attr(feature = "full", diesel(table_name = post_like))] -pub struct PostLikeForm { +pub(crate) struct PostLikeForm { pub post_id: PostId, pub person_id: PersonId, pub score: i16, + pub published: Option>, } #[derive(PartialEq, Eq, Debug)] diff --git a/crates/db_schema/src/traits.rs b/crates/db_schema/src/traits.rs index 74f5ea009c..3df67480ef 100644 --- a/crates/db_schema/src/traits.rs +++ b/crates/db_schema/src/traits.rs @@ -15,6 +15,7 @@ use diesel_async::{ AsyncPgConnection, RunQueryDsl, }; +use lemmy_utils::settings::structs::Settings; /// Returned by `diesel::delete` pub type Delete = DeleteStatement<::Table, ::WhereClause>; @@ -94,9 +95,14 @@ pub trait Joinable { #[async_trait] pub trait Likeable { - type Form; type IdType; - async fn like(pool: &mut DbPool<'_>, form: &Self::Form) -> Result + async fn like( + pool: &mut DbPool<'_>, + person_id: PersonId, + item_id: Self::IdType, + score: i16, + settings: &Settings, + ) -> Result where Self: Sized; async fn remove( diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index 55fea4d66b..b0171d2443 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -438,7 +438,6 @@ mod tests { Comment, CommentInsertForm, CommentLike, - CommentLikeForm, CommentSaved, CommentSavedForm, CommentUpdateForm, @@ -466,7 +465,7 @@ mod tests { CommunityVisibility, SubscribedType, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use pretty_assertions::assert_eq; use serial_test::serial; @@ -599,13 +598,15 @@ mod tests { }; assert_eq!(expected_block, inserted_block); - let comment_like_form = CommentLikeForm { - comment_id: inserted_comment_0.id, - person_id: inserted_timmy_person.id, - score: 1, - }; - - let _inserted_comment_like = CommentLike::like(pool, &comment_like_form).await?; + let settings = Settings::default(); + CommentLike::like( + pool, + inserted_timmy_person.id, + inserted_comment_0.id, + 1, + &settings, + ) + .await?; let timmy_local_user_view = LocalUserView { local_user: inserted_timmy_local_user.clone(), @@ -698,12 +699,15 @@ mod tests { PersonBlock::unblock(pool, &timmy_unblocks_sara_form).await?; // Like a new comment - let comment_like_form = CommentLikeForm { - comment_id: data.inserted_comment_1.id, - person_id: data.timmy_local_user_view.person.id, - score: 1, - }; - CommentLike::like(pool, &comment_like_form).await?; + let settings = Settings::default(); + CommentLike::like( + pool, + data.timmy_local_user_view.person.id, + data.inserted_comment_1.id, + 1, + &settings, + ) + .await?; let read_liked_comment_views = CommentQuery { local_user: Some(&data.timmy_local_user_view.local_user), diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index d05d668c20..fdcd23c6d7 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -759,7 +759,6 @@ mod tests { PostHide, PostInsertForm, PostLike, - PostLikeForm, PostRead, PostSaved, PostSavedForm, @@ -773,7 +772,7 @@ mod tests { PostSortType, SubscribedType, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use pretty_assertions::assert_eq; use serial_test::serial; use std::{collections::HashSet, time::Duration}; @@ -1114,18 +1113,21 @@ mod tests { let pool = &mut pool.into(); let mut data = init_data(pool).await?; - let post_like_form = PostLikeForm { - post_id: data.inserted_post.id, - person_id: data.local_user_view.person.id, - score: 1, - }; - - let inserted_post_like = PostLike::like(pool, &post_like_form).await?; + let settings = Settings::default(); + let inserted_post_like = PostLike::like( + pool, + data.local_user_view.person.id, + data.inserted_post.id, + 1, + &settings, + ) + .await?; let expected_post_like = PostLike { post_id: data.inserted_post.id, person_id: data.local_user_view.person.id, score: 1, + published: None, }; assert_eq!(expected_post_like, inserted_post_like); @@ -1173,19 +1175,24 @@ mod tests { // Like both the bot post, and your own // The liked_only should not show your own post - let post_like_form = PostLikeForm { - post_id: data.inserted_post.id, - person_id: data.local_user_view.person.id, - score: 1, - }; - PostLike::like(pool, &post_like_form).await?; + let settings = Settings::default(); + PostLike::like( + pool, + data.local_user_view.person.id, + data.inserted_post.id, + 1, + &settings, + ) + .await?; - let bot_post_like_form = PostLikeForm { - post_id: data.inserted_bot_post.id, - person_id: data.local_user_view.person.id, - score: 1, - }; - PostLike::like(pool, &bot_post_like_form).await?; + PostLike::like( + pool, + data.local_user_view.person.id, + data.inserted_bot_post.id, + 1, + &settings, + ) + .await?; // Read the liked only let read_liked_post_listing = PostQuery { diff --git a/crates/db_views/src/structs.rs b/crates/db_views/src/structs.rs index 3c219d63fb..7e295e1a43 100644 --- a/crates/db_views/src/structs.rs +++ b/crates/db_views/src/structs.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; #[cfg(feature = "full")] use diesel::Queryable; use lemmy_db_schema::{ @@ -216,6 +217,7 @@ pub struct VoteView { pub creator: Person, pub creator_banned_from_community: bool, pub score: i16, + pub published: Option>, } #[skip_serializing_none] diff --git a/crates/db_views/src/vote_view.rs b/crates/db_views/src/vote_view.rs index 0fd64decad..357a2ecda9 100644 --- a/crates/db_views/src/vote_view.rs +++ b/crates/db_views/src/vote_view.rs @@ -40,6 +40,7 @@ impl VoteView { person::all_columns, community_person_ban::community_id.nullable().is_not_null(), post_like::score, + post_like::published, )) .order_by(post_like::score) .limit(limit) @@ -74,6 +75,7 @@ impl VoteView { person::all_columns, community_person_ban::community_id.nullable().is_not_null(), comment_like::score, + comment_like::published, )) .order_by(comment_like::score) .limit(limit) @@ -89,16 +91,16 @@ mod tests { use crate::structs::VoteView; use lemmy_db_schema::{ source::{ - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentInsertForm, CommentLike}, community::{Community, CommunityInsertForm, CommunityPersonBan, CommunityPersonBanForm}, instance::Instance, person::{Person, PersonInsertForm}, - post::{Post, PostInsertForm, PostLike, PostLikeForm}, + post::{Post, PostInsertForm, PostLike}, }, traits::{Bannable, Crud, Likeable}, utils::build_db_pool_for_tests, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use pretty_assertions::assert_eq; use serial_test::serial; @@ -141,31 +143,24 @@ mod tests { let inserted_comment = Comment::create(pool, &comment_form, None).await?; // Timmy upvotes his own post - let timmy_post_vote_form = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_timmy.id, - score: 1, - }; - PostLike::like(pool, &timmy_post_vote_form).await?; + let settings = Settings::default(); + PostLike::like(pool, inserted_timmy.id, inserted_post.id, 1, &settings).await?; // Sara downvotes timmy's post - let sara_post_vote_form = PostLikeForm { - post_id: inserted_post.id, - person_id: inserted_sara.id, - score: -1, - }; - PostLike::like(pool, &sara_post_vote_form).await?; + PostLike::like(pool, inserted_sara.id, inserted_post.id, -1, &settings).await?; let expected_post_vote_views = [ VoteView { creator: inserted_sara.clone(), creator_banned_from_community: false, score: -1, + published: None, }, VoteView { creator: inserted_timmy.clone(), creator_banned_from_community: false, score: 1, + published: None, }, ]; @@ -173,31 +168,23 @@ mod tests { assert_eq!(read_post_vote_views, expected_post_vote_views); // Timothy votes down his own comment - let timmy_comment_vote_form = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: inserted_timmy.id, - score: -1, - }; - CommentLike::like(pool, &timmy_comment_vote_form).await?; + CommentLike::like(pool, inserted_timmy.id, inserted_comment.id, -1, &settings).await?; // Sara upvotes timmy's comment - let sara_comment_vote_form = CommentLikeForm { - comment_id: inserted_comment.id, - person_id: inserted_sara.id, - score: 1, - }; - CommentLike::like(pool, &sara_comment_vote_form).await?; + CommentLike::like(pool, inserted_sara.id, inserted_comment.id, 1, &settings).await?; let expected_comment_vote_views = [ VoteView { creator: inserted_timmy.clone(), creator_banned_from_community: false, score: -1, + published: None, }, VoteView { creator: inserted_sara.clone(), creator_banned_from_community: false, score: 1, + published: None, }, ]; diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs index 8c28d908a2..d11bc3abcb 100644 --- a/crates/utils/src/settings/structs.rs +++ b/crates/utils/src/settings/structs.rs @@ -128,6 +128,11 @@ pub struct DatabaseConfig { /// Maximum number of active sql connections #[default(30)] pub pool_size: usize, + + /// Set true to store the time when votes were cast. Requires more storage space but can be + /// used to detect vote manipulation. + #[default(false)] + pub store_vote_timestamps: bool, } #[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)] diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql index 928530641c..4373e0cf62 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/down.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/down.sql @@ -1,9 +1,17 @@ +-- make published not null again and add default ALTER TABLE post_like - ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + ALTER COLUMN published SET NOT NULL; + +ALTER TABLE post_like + ALTER COLUMN published SET DEFAULT now(); + +ALTER TABLE comment_like + ALTER COLUMN published DROP NOT NULL; ALTER TABLE comment_like - ADD COLUMN published timestamptz NOT NULL DEFAULT now(); + ALTER COLUMN published SET DEFAULT now(); +-- restore comment_like.post_id ALTER TABLE comment_like ADD COLUMN post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql index 2cf906a09f..65fe510cc2 100644 --- a/migrations/2024-10-17-091053_vote-no-timestamp/up.sql +++ b/migrations/2024-10-17-091053_vote-no-timestamp/up.sql @@ -1,21 +1,18 @@ --- set all column values to null to reclaim disk space --- https://dba.stackexchange.com/a/117513 +-- make published columns nullable and remove default value ALTER TABLE post_like ALTER COLUMN published DROP NOT NULL; -UPDATE - post_like -SET - published = NULL; +ALTER TABLE post_like + ALTER COLUMN published DROP DEFAULT; ALTER TABLE comment_like ALTER COLUMN published DROP NOT NULL; -UPDATE - comment_like -SET - published = NULL; +ALTER TABLE comment_like + ALTER COLUMN published DROP DEFAULT; +-- get rid of comment_like.post_id, setting null first to reclaim space +-- https://dba.stackexchange.com/a/117513 ALTER TABLE comment_like ALTER COLUMN post_id DROP NOT NULL; @@ -25,12 +22,6 @@ SET post_id = NULL; -- drop the columns -ALTER TABLE post_like - DROP published; - -ALTER TABLE comment_like - DROP published; - ALTER TABLE comment_like DROP post_id;