Adding temporary bans. Fixes #1423 (#1999)

* Adding temporary bans. Fixes #1423

* Adding ban_expires to person

* Fix clippy

* Removing ban_expires from federated fields.

* Trying to add expires to blockcommunity apub.
This commit is contained in:
Dessalines 2022-01-08 07:37:07 -05:00 committed by GitHub
parent 41b90bb162
commit e65c45f152
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 179 additions and 32 deletions

View file

@ -214,6 +214,7 @@ impl Perform for BanFromCommunity {
let community_id = data.community_id;
let banned_person_id = data.person_id;
let expires = data.expires.map(naive_from_unix);
// Verify that only mods or admins can ban
is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?;
@ -221,6 +222,7 @@ impl Perform for BanFromCommunity {
let community_user_ban_form = CommunityPersonBanForm {
community_id: data.community_id,
person_id: data.person_id,
expires: Some(expires),
};
let community: ApubCommunity = blocking(context.pool(), move |conn: &'_ _| {
@ -257,6 +259,7 @@ impl Perform for BanFromCommunity {
&community,
&banned_person,
&local_user_view.person.clone().into(),
expires,
context,
)
.await?;
@ -304,9 +307,6 @@ impl Perform for BanFromCommunity {
}
// Mod tables
// TODO eventually do correct expires
let expires = data.expires.map(naive_from_unix);
let form = ModBanFromCommunityForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,

View file

@ -256,6 +256,7 @@ impl Perform for SaveUserSettings {
shared_inbox_url: None,
matrix_user_id,
bot_account,
ban_expires: None,
};
blocking(context.pool(), move |conn| {
@ -452,7 +453,9 @@ impl Perform for BanPerson {
let ban = data.ban;
let banned_person_id = data.person_id;
let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban);
let expires = data.expires.map(naive_from_unix);
let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban, expires);
blocking(context.pool(), ban_person)
.await?
.map_err(LemmyError::from)
@ -495,8 +498,6 @@ impl Perform for BanPerson {
}
// Mod tables
let expires = data.expires.map(naive_from_unix);
let form = ModBanForm {
mod_person_id: local_user_view.person.id,
other_person_id: data.person_id,

View file

@ -132,7 +132,7 @@ pub async fn get_local_user_view_from_jwt(
let local_user_view =
blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??;
// Check for a site ban
if local_user_view.person.banned {
if local_user_view.person.is_banned() {
return Err(LemmyError::from_message("site_ban"));
}
@ -187,7 +187,7 @@ pub async fn get_local_user_settings_view_from_jwt(
})
.await??;
// Check for a site ban
if local_user_view.person.banned {
if local_user_view.person.is_banned() {
return Err(LemmyError::from_message("site_ban"));
}

View file

@ -9,5 +9,6 @@
],
"target": "http://enterprise.lemmy.ml/c/main",
"type": "Block",
"expires": "2021-11-01T12:23:50.151874+00:00",
"id": "http://enterprise.lemmy.ml/activities/block/5d42fffb-0903-4625-86d4-0b39bb344fc2"
}
}

View file

@ -12,6 +12,7 @@ use crate::{
protocol::activities::community::block_user::BlockUserFromCommunity,
};
use activitystreams_kinds::{activity::BlockType, public};
use chrono::NaiveDateTime;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
@ -27,7 +28,7 @@ use lemmy_db_schema::{
},
traits::{Bannable, Followable},
};
use lemmy_utils::LemmyError;
use lemmy_utils::{utils::convert_datetime, LemmyError};
use lemmy_websocket::LemmyContext;
impl BlockUserFromCommunity {
@ -35,6 +36,7 @@ impl BlockUserFromCommunity {
community: &ApubCommunity,
target: &ApubPerson,
actor: &ApubPerson,
expires: Option<NaiveDateTime>,
context: &LemmyContext,
) -> Result<BlockUserFromCommunity, LemmyError> {
Ok(BlockUserFromCommunity {
@ -48,6 +50,7 @@ impl BlockUserFromCommunity {
BlockType::Block,
&context.settings().get_protocol_and_hostname(),
)?,
expires: expires.map(convert_datetime),
unparsed: Default::default(),
})
}
@ -57,9 +60,10 @@ impl BlockUserFromCommunity {
community: &ApubCommunity,
target: &ApubPerson,
actor: &ApubPerson,
expires: Option<NaiveDateTime>,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let block = BlockUserFromCommunity::new(community, target, actor, context)?;
let block = BlockUserFromCommunity::new(community, target, actor, expires, context)?;
let block_id = block.id.clone();
let activity = AnnouncableActivities::BlockUserFromCommunity(block);
@ -101,6 +105,7 @@ impl ActivityHandler for BlockUserFromCommunity {
let community_user_ban_form = CommunityPersonBanForm {
community_id: community.id,
person_id: blocked_user.id,
expires: Some(self.expires.map(|u| u.naive_local())),
};
blocking(context.pool(), move |conn: &'_ _| {

View file

@ -36,7 +36,7 @@ impl UndoBlockUserFromCommunity {
actor: &ApubPerson,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let block = BlockUserFromCommunity::new(community, target, actor, context)?;
let block = BlockUserFromCommunity::new(community, target, actor, None, context)?;
let id = generate_activity_id(
UndoType::Undo,
@ -93,6 +93,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
let community_user_ban_form = CommunityPersonBanForm {
community_id: community.id,
person_id: blocked_user.id,
expires: None,
};
blocking(context.pool(), move |conn: &'_ _| {

View file

@ -149,6 +149,7 @@ impl ApubObject for ApubPerson {
name: person.preferred_username,
display_name: Some(person.name),
banned: None,
ban_expires: None,
deleted: None,
avatar: Some(person.icon.map(|i| i.url.into())),
banner: Some(person.image.map(|i| i.url.into())),

View file

@ -3,6 +3,7 @@ use crate::{
protocol::Unparsed,
};
use activitystreams_kinds::activity::BlockType;
use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::object_id::ObjectId;
use serde::{Deserialize, Serialize};
use url::Url;
@ -22,4 +23,5 @@ pub struct BlockUserFromCommunity {
pub(crate) id: Url,
#[serde(flatten)]
pub(crate) unparsed: Unparsed,
pub(crate) expires: Option<DateTime<FixedOffset>>,
}

View file

@ -225,6 +225,9 @@ impl Bannable for CommunityPersonBan {
use crate::schema::community_person_ban::dsl::*;
insert_into(community_person_ban)
.values(community_person_ban_form)
.on_conflict((community_id, person_id))
.do_update()
.set(community_person_ban_form)
.get_result::<Self>(conn)
}
@ -383,6 +386,7 @@ mod tests {
let community_person_ban_form = CommunityPersonBanForm {
community_id: inserted_community.id,
person_id: inserted_person.id,
expires: None,
};
let inserted_community_person_ban =
@ -393,6 +397,7 @@ mod tests {
community_id: inserted_community.id,
person_id: inserted_person.id,
published: inserted_community_person_ban.published,
expires: None,
};
let read_community = Community::read(&conn, inserted_community.id).unwrap();

View file

@ -3,7 +3,7 @@ use crate::{
naive_now,
newtypes::{DbUrl, PersonId},
schema::person::dsl::*,
source::person::{Person, PersonForm},
source::person::{Person, PersonForm, PersonSafe},
traits::Crud,
};
use diesel::{dsl::*, result::Error, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
@ -30,6 +30,7 @@ mod safe_type {
matrix_user_id,
admin,
bot_account,
ban_expires,
);
impl ToSafe for Person {
@ -53,6 +54,7 @@ mod safe_type {
matrix_user_id,
admin,
bot_account,
ban_expires,
)
}
}
@ -79,6 +81,7 @@ mod safe_type_alias_1 {
matrix_user_id,
admin,
bot_account,
ban_expires,
);
impl ToSafe for PersonAlias1 {
@ -102,6 +105,7 @@ mod safe_type_alias_1 {
matrix_user_id,
admin,
bot_account,
ban_expires,
)
}
}
@ -128,6 +132,7 @@ mod safe_type_alias_2 {
matrix_user_id,
admin,
bot_account,
ban_expires,
);
impl ToSafe for PersonAlias2 {
@ -151,6 +156,7 @@ mod safe_type_alias_2 {
matrix_user_id,
admin,
bot_account,
ban_expires,
)
}
}
@ -179,9 +185,14 @@ impl Crud for Person {
}
impl Person {
pub fn ban_person(conn: &PgConnection, person_id: PersonId, ban: bool) -> Result<Self, Error> {
pub fn ban_person(
conn: &PgConnection,
person_id: PersonId,
ban: bool,
expires: Option<chrono::NaiveDateTime>,
) -> Result<Self, Error> {
diesel::update(person.find(person_id))
.set(banned.eq(ban))
.set((banned.eq(ban), ban_expires.eq(expires)))
.get_result::<Self>(conn)
}
@ -259,6 +270,24 @@ impl Person {
.set(deleted.eq(new_deleted))
.get_result::<Self>(conn)
}
pub fn is_banned(&self) -> bool {
is_banned(self.banned, self.ban_expires)
}
}
impl PersonSafe {
pub fn is_banned(&self) -> bool {
is_banned(self.banned, self.ban_expires)
}
}
fn is_banned(banned_: bool, expires: Option<chrono::NaiveDateTime>) -> bool {
if let Some(expires) = expires {
banned_ && expires.gt(&naive_now())
} else {
banned_
}
}
#[cfg(test)]
@ -298,6 +327,7 @@ mod tests {
inbox_url: inserted_person.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
};
let read_person = Person::read(&conn, inserted_person.id).unwrap();

View file

@ -136,6 +136,7 @@ table! {
community_id -> Int4,
person_id -> Int4,
published -> Timestamp,
expires -> Nullable<Timestamp>,
}
}
@ -304,6 +305,7 @@ table! {
matrix_user_id -> Nullable<Text>,
admin -> Bool,
bot_account -> Bool,
ban_expires -> Nullable<Timestamp>,
}
}
@ -529,6 +531,7 @@ table! {
matrix_user_id -> Nullable<Text>,
admin -> Bool,
bot_account -> Bool,
ban_expires -> Nullable<Timestamp>,
}
}
@ -554,6 +557,7 @@ table! {
matrix_user_id -> Nullable<Text>,
admin -> Bool,
bot_account -> Bool,
ban_expires -> Nullable<Timestamp>,
}
}

View file

@ -95,6 +95,7 @@ pub struct CommunityPersonBan {
pub community_id: CommunityId,
pub person_id: PersonId,
pub published: chrono::NaiveDateTime,
pub expires: Option<chrono::NaiveDateTime>,
}
#[derive(Insertable, AsChangeset, Clone)]
@ -102,6 +103,7 @@ pub struct CommunityPersonBan {
pub struct CommunityPersonBanForm {
pub community_id: CommunityId,
pub person_id: PersonId,
pub expires: Option<Option<chrono::NaiveDateTime>>,
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]

View file

@ -27,6 +27,7 @@ pub struct Person {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
/// A safe representation of person, without the sensitive info
@ -50,6 +51,7 @@ pub struct PersonSafe {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
@ -75,6 +77,7 @@ pub struct PersonAlias1 {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
@ -97,6 +100,7 @@ pub struct PersonSafeAlias1 {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
@ -122,6 +126,7 @@ pub struct PersonAlias2 {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
@ -144,6 +149,7 @@ pub struct PersonSafeAlias2 {
pub matrix_user_id: Option<String>,
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
#[derive(Insertable, AsChangeset, Clone, Default)]
@ -168,4 +174,5 @@ pub struct PersonForm {
pub matrix_user_id: Option<Option<String>>,
pub admin: Option<bool>,
pub bot_account: Option<bool>,
pub ban_expires: Option<Option<chrono::NaiveDateTime>>,
}

View file

@ -1,4 +1,4 @@
use diesel::{result::Error, *};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
aggregates::comment_aggregates::CommentAggregates,
limit_and_offset,
@ -88,7 +88,12 @@ impl CommentReportView {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -229,7 +234,12 @@ impl<'a> CommentReportQueryBuilder<'a> {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -444,6 +454,7 @@ mod tests {
inbox_url: inserted_jessica.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
comment_creator: PersonSafeAlias1 {
id: inserted_timmy.id,
@ -463,6 +474,7 @@ mod tests {
inbox_url: inserted_timmy.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
creator_banned_from_community: false,
counts: CommentAggregates {
@ -499,6 +511,7 @@ mod tests {
inbox_url: inserted_sara.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
};
// Do a batch read of timmys reports
@ -554,6 +567,7 @@ mod tests {
inbox_url: inserted_timmy.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
});
assert_eq!(

View file

@ -1,4 +1,4 @@
use diesel::{result::Error, *};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
aggregates::comment_aggregates::CommentAggregates,
functions::hot_rank,
@ -98,7 +98,12 @@ impl CommentView {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -345,7 +350,12 @@ impl<'a> CommentQueryBuilder<'a> {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -646,6 +656,7 @@ mod tests {
inbox_url: inserted_person.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
recipient: None,
post: Post {

View file

@ -1,4 +1,4 @@
use diesel::{result::Error, *};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
aggregates::post_aggregates::PostAggregates,
limit_and_offset,
@ -79,7 +79,12 @@ impl PostReportView {
community_person_ban::table.on(
post::community_id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(post::creator_id)),
.and(community_person_ban::person_id.eq(post::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -209,7 +214,12 @@ impl<'a> PostReportQueryBuilder<'a> {
community_person_ban::table.on(
post::community_id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(post::creator_id)),
.and(community_person_ban::person_id.eq(post::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -422,6 +432,7 @@ mod tests {
inbox_url: inserted_jessica.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
post_creator: PersonSafeAlias1 {
id: inserted_timmy.id,
@ -441,6 +452,7 @@ mod tests {
inbox_url: inserted_timmy.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
creator_banned_from_community: false,
my_vote: None,
@ -482,6 +494,7 @@ mod tests {
inbox_url: inserted_sara.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
};
// Do a batch read of timmys reports
@ -535,6 +548,7 @@ mod tests {
inbox_url: inserted_timmy.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
});
assert_eq!(

View file

@ -1,4 +1,4 @@
use diesel::{pg::Pg, result::Error, *};
use diesel::{dsl::*, pg::Pg, result::Error, *};
use lemmy_db_schema::{
aggregates::post_aggregates::PostAggregates,
functions::hot_rank,
@ -86,7 +86,12 @@ impl PostView {
community_person_ban::table.on(
post::community_id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(post::creator_id)),
.and(community_person_ban::person_id.eq(post::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.inner_join(post_aggregates::table)
@ -284,7 +289,12 @@ impl<'a> PostQueryBuilder<'a> {
community_person_ban::table.on(
post::community_id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(post::creator_id)),
.and(community_person_ban::person_id.eq(post::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.inner_join(post_aggregates::table)
@ -653,6 +663,7 @@ mod tests {
inbox_url: inserted_person.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
},
creator_banned_from_community: false,
community: CommunitySafe {

View file

@ -290,6 +290,7 @@ mod tests {
actor_id: inserted_sara_person.actor_id.to_owned(),
local: true,
banned: false,
ban_expires: None,
deleted: false,
admin: false,
bot_account: false,
@ -358,6 +359,7 @@ mod tests {
actor_id: inserted_timmy_person.actor_id.to_owned(),
local: true,
banned: false,
ban_expires: None,
deleted: false,
admin: true,
bot_account: false,

View file

@ -1,4 +1,4 @@
use diesel::{result::Error, *};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
schema::{community, community_person_ban, person},
@ -31,6 +31,11 @@ impl CommunityPersonBanView {
))
.filter(community_person_ban::community_id.eq(from_community_id))
.filter(community_person_ban::person_id.eq(from_person_id))
.filter(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
)
.order_by(community_person_ban::published)
.first::<(CommunitySafe, PersonSafe)>(conn)?;

View file

@ -1,4 +1,4 @@
use diesel::{result::Error, *};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
aggregates::comment_aggregates::CommentAggregates,
functions::hot_rank,
@ -96,7 +96,12 @@ impl PersonMentionView {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(
@ -241,7 +246,12 @@ impl<'a> PersonMentionQueryBuilder<'a> {
community_person_ban::table.on(
community::id
.eq(community_person_ban::community_id)
.and(community_person_ban::person_id.eq(comment::creator_id)),
.and(community_person_ban::person_id.eq(comment::creator_id))
.and(
community_person_ban::expires
.is_null()
.or(community_person_ban::expires.gt(now)),
),
),
)
.left_join(

View file

@ -44,7 +44,13 @@ impl PersonViewSafe {
let banned = person::table
.inner_join(person_aggregates::table)
.select((Person::safe_columns_tuple(), person_aggregates::all_columns))
.filter(person::banned.eq(true))
.filter(
person::banned.eq(true).and(
person::ban_expires
.is_null()
.or(person::ban_expires.gt(now)),
),
)
.load::<PersonViewSafeTuple>(conn)?;
Ok(Self::from_tuple_to_vec(banned))

View file

@ -0,0 +1,7 @@
drop view person_alias_1, person_alias_2;
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;

View file

@ -0,0 +1,8 @@
-- 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;
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;