add setting store_vote_timestamps

This commit is contained in:
Felix Ableitner 2024-10-17 15:08:56 +02:00
parent 08055b9dfb
commit fd8a6b46f7
24 changed files with 285 additions and 256 deletions

View file

@ -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: {

View file

@ -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(

View file

@ -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?;

View file

@ -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()),

View file

@ -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?;

View file

@ -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?;

View file

@ -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?;

View file

@ -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<LemmyContext>,
) -> 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<LemmyContext>,
) -> 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(())
}

View file

@ -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?;

View file

@ -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

View file

@ -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?;

View file

@ -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<Self, Error> {
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<Self, Error> {
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::<Self>(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

View file

@ -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<Self, Error> {
async fn like(
pool: &mut DbPool<'_>,
person_id: PersonId,
post_id: Self::IdType,
score: i16,
settings: &Settings,
) -> Result<Self, Error> {
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::<Self>(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

View file

@ -124,6 +124,7 @@ diesel::table! {
person_id -> Int4,
comment_id -> Int4,
score -> Int2,
published -> Nullable<Timestamptz>,
}
}
@ -814,6 +815,7 @@ diesel::table! {
post_id -> Int4,
person_id -> Int4,
score -> Int2,
published -> Nullable<Timestamptz>,
}
}

View file

@ -103,15 +103,17 @@ pub struct CommentLike {
pub person_id: PersonId,
pub comment_id: CommentId,
pub score: i16,
pub published: Option<DateTime<Utc>>,
}
#[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<DateTime<Utc>>,
}
#[derive(PartialEq, Eq, Debug)]

View file

@ -150,15 +150,17 @@ pub struct PostLike {
pub post_id: PostId,
pub person_id: PersonId,
pub score: i16,
pub published: Option<DateTime<Utc>>,
}
#[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<DateTime<Utc>>,
}
#[derive(PartialEq, Eq, Debug)]

View file

@ -15,6 +15,7 @@ use diesel_async::{
AsyncPgConnection,
RunQueryDsl,
};
use lemmy_utils::settings::structs::Settings;
/// Returned by `diesel::delete`
pub type Delete<T> = DeleteStatement<<T as HasTable>::Table, <T as IntoUpdateTarget>::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<Self, Error>
async fn like(
pool: &mut DbPool<'_>,
person_id: PersonId,
item_id: Self::IdType,
score: i16,
settings: &Settings,
) -> Result<Self, Error>
where
Self: Sized;
async fn remove(

View file

@ -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),

View file

@ -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 {

View file

@ -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<DateTime<Utc>>,
}
#[skip_serializing_none]

View file

@ -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,
},
];

View file

@ -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)]

View file

@ -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
ADD COLUMN published timestamptz NOT NULL DEFAULT now();
ALTER COLUMN published DROP NOT NULL;
ALTER TABLE comment_like
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;

View file

@ -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;