let bio = diesel_option_overwrite(&data.bio);
let display_name = diesel_option_overwrite(&data.display_name);
let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id);
+ let bot_account = data.bot_account;
if let Some(Some(bio)) = &bio {
if bio.chars().count() > 300 {
last_refreshed_at: None,
shared_inbox_url: None,
matrix_user_id,
+ bot_account,
};
let person_res = blocking(context.pool(), move |conn| {
email,
password_encrypted,
show_nsfw: data.show_nsfw,
+ show_bot_accounts: data.show_bot_accounts,
show_scores: data.show_scores,
theme: data.theme.to_owned(),
default_sort_type,
let limit = data.limit;
let unread_only = data.unread_only;
let person_id = local_user_view.person.id;
+ let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
+
let replies = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn)
.sort(&sort)
.unread_only(unread_only)
.recipient_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.my_person_id(person_id)
.page(page)
.limit(limit)
get_local_user_view_from_jwt_opt,
is_admin,
site::*,
+ user_show_bot_accounts,
+ user_show_nsfw,
};
use lemmy_apub::fetcher::search::search_by_apub_id;
use lemmy_db_queries::{source::site::Site_, Crud, SearchType, SortType};
}
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+
+ let show_nsfw = user_show_nsfw(&local_user_view);
+ let show_bot_accounts = user_show_bot_accounts(&local_user_view);
+
let person_id = local_user_view.map(|u| u.person.id);
let type_ = SearchType::from_str(&data.type_)?;
posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn)
.sort(&sort)
- .show_nsfw(true)
+ .show_nsfw(show_nsfw)
+ .show_bot_accounts(show_bot_accounts)
.community_id(community_id)
.community_name(community_name)
.my_person_id(person_id)
CommentQueryBuilder::create(&conn)
.sort(&sort)
.search_term(q)
+ .show_bot_accounts(show_bot_accounts)
.my_person_id(person_id)
.page(page)
.limit(limit)
posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn)
.sort(&sort)
- .show_nsfw(true)
+ .show_nsfw(show_nsfw)
+ .show_bot_accounts(show_bot_accounts)
.community_id(community_id)
.community_name(community_name)
.my_person_id(person_id)
CommentQueryBuilder::create(conn)
.sort(&sort)
.search_term(q)
+ .show_bot_accounts(show_bot_accounts)
.my_person_id(person_id)
.page(page)
.limit(limit)
posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn)
.sort(&sort)
- .show_nsfw(true)
+ .show_nsfw(show_nsfw)
+ .show_bot_accounts(show_bot_accounts)
.my_person_id(person_id)
.community_id(community_id)
.community_name(community_name)
Ok(())
}
+/// A helper method for showing the bot account
+pub fn user_show_bot_accounts(local_user_view: &Option<LocalUserView>) -> bool {
+ match local_user_view {
+ Some(uv) => uv.to_owned().local_user.show_bot_accounts,
+ None => true,
+ }
+}
+
+/// A helper method for showing nsfw
+pub fn user_show_nsfw(local_user_view: &Option<LocalUserView>) -> bool {
+ match &local_user_view {
+ Some(uv) => uv.local_user.show_nsfw,
+ None => false,
+ }
+}
+
pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> {
blocking(pool, move |conn| Post::read(conn, post_id))
.await?
pub matrix_user_id: Option<String>,
pub show_avatars: Option<bool>,
pub send_notifications_to_email: Option<bool>,
+ pub bot_account: Option<bool>,
+ pub show_bot_accounts: Option<bool>,
pub auth: String,
}
use crate::PerformCrud;
use actix_web::web::Data;
-use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt};
+use lemmy_api_common::{
+ blocking,
+ comment::*,
+ get_local_user_view_from_jwt_opt,
+ user_show_bot_accounts,
+};
use lemmy_db_queries::{ListingType, SortType};
use lemmy_db_views::comment_view::CommentQueryBuilder;
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
) -> Result<GetCommentsResponse, LemmyError> {
let data: &GetComments = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+
+ let show_bot_accounts = user_show_bot_accounts(&local_user_view);
let person_id = local_user_view.map(|u| u.person.id);
let type_ = ListingType::from_str(&data.type_)?;
.community_id(community_id)
.community_name(community_name)
.my_person_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.page(page)
.limit(limit)
.list()
use crate::PerformCrud;
use actix_web::web::Data;
-use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, post::*};
+use lemmy_api_common::{
+ blocking,
+ get_local_user_view_from_jwt_opt,
+ post::*,
+ user_show_bot_accounts,
+ user_show_nsfw,
+};
use lemmy_db_queries::{ListingType, SortType};
use lemmy_db_views::{
comment_view::CommentQueryBuilder,
) -> Result<GetPostResponse, LemmyError> {
let data: &GetPost = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+
+ let show_bot_accounts = user_show_bot_accounts(&local_user_view);
+
let person_id = local_user_view.map(|u| u.person.id);
let id = data.id;
let comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn)
.my_person_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.post_id(id)
.limit(9999)
.list()
let person_id = local_user_view.to_owned().map(|l| l.person.id);
- let show_nsfw = match &local_user_view {
- Some(uv) => uv.local_user.show_nsfw,
- None => false,
- };
+ let show_nsfw = user_show_nsfw(&local_user_view);
+ let show_bot_accounts = user_show_bot_accounts(&local_user_view);
let type_ = ListingType::from_str(&data.type_)?;
let sort = SortType::from_str(&data.sort)?;
.listing_type(&type_)
.sort(&sort)
.show_nsfw(show_nsfw)
+ .show_bot_accounts(show_bot_accounts)
.community_id(community_id)
.community_name(community_name)
.saved_only(saved_only)
email: Some(data.email.to_owned()),
password_encrypted: data.password.to_owned(),
show_nsfw: Some(data.show_nsfw),
+ show_bot_accounts: Some(true),
theme: Some("browser".into()),
default_sort_type: Some(SortType::Active as i16),
default_listing_type: Some(ListingType::Subscribed as i16),
use crate::PerformCrud;
use actix_web::web::Data;
-use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*};
+use lemmy_api_common::{
+ blocking,
+ get_local_user_view_from_jwt_opt,
+ person::*,
+ user_show_bot_accounts,
+ user_show_nsfw,
+};
use lemmy_db_queries::{source::person::Person_, SortType};
use lemmy_db_schema::source::person::*;
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
let data: &GetPersonDetails = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
- let show_nsfw = match &local_user_view {
- Some(uv) => uv.local_user.show_nsfw,
- None => false,
- };
+ let show_nsfw = user_show_nsfw(&local_user_view);
+ let show_bot_accounts = user_show_bot_accounts(&local_user_view);
let sort = SortType::from_str(&data.sort)?;
let mut posts_query = PostQueryBuilder::create(conn)
.sort(&sort)
.show_nsfw(show_nsfw)
+ .show_bot_accounts(show_bot_accounts)
.saved_only(saved_only)
.community_id(community_id)
.my_person_id(person_id)
let mut comments_query = CommentQueryBuilder::create(conn)
.my_person_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.sort(&sort)
.saved_only(saved_only)
.community_id(community_id)
pub type GroupExt =
Ext2<actor::ApActor<ApObject<actor::Group>>, GroupExtension, PublicKeyExtension>;
/// Activitystreams type for person
-type PersonExt = Ext2<actor::ApActor<ApObject<actor::Person>>, PersonExtension, PublicKeyExtension>;
+type PersonExt =
+ Ext2<actor::ApActor<ApObject<actor::Actor<UserTypes>>>, PersonExtension, PublicKeyExtension>;
/// Activitystreams type for post
pub type PageExt = Ext1<ApObject<Page>, PageExtension>;
pub type NoteExt = ApObject<Note>;
+#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq)]
+pub enum UserTypes {
+ Person,
+ Service,
+}
+
pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
/// Checks if the ID is allowed for sending or receiving.
},
ActorType,
PersonExt,
+ UserTypes,
};
use activitystreams::{
- actor::{ApActor, Endpoints, Person},
- object::{ApObject, Image, Tombstone},
- prelude::*,
+ actor::{Actor, ApActor, ApActorExt, Endpoints},
+ base::{BaseExt, ExtendsExt},
+ object::{ApObject, Image, Object, ObjectExt, Tombstone},
};
use activitystreams_ext::Ext2;
use anyhow::Context;
type ApubType = PersonExt;
async fn to_apub(&self, _pool: &DbPool) -> Result<PersonExt, LemmyError> {
- let mut person = ApObject::new(Person::new());
+ let object = Object::<UserTypes>::new_none_type();
+ let mut actor = Actor(object);
+ let kind = if self.bot_account {
+ UserTypes::Service
+ } else {
+ UserTypes::Person
+ };
+ actor.set_kind(kind);
+ let mut person = ApObject::new(actor);
+
person
.set_many_contexts(lemmy_context()?)
.set_id(self.actor_id.to_owned().into_inner())
bio: Some(bio),
local: Some(false),
admin: Some(false),
+ bot_account: Some(person.inner.is_kind(&UserTypes::Service)),
private_key: None,
public_key: Some(Some(person.ext_two.public_key.to_owned().public_key_pem)),
last_refreshed_at: Some(naive_now()),
show_avatars,
send_notifications_to_email,
validator_time,
+ show_bot_accounts,
show_scores,
);
show_avatars,
send_notifications_to_email,
validator_time,
+ show_bot_accounts,
show_scores,
)
}
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
);
impl ToSafe for Person {
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
)
}
}
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
);
impl ToSafe for PersonAlias1 {
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
)
}
}
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
);
impl ToSafe for PersonAlias2 {
shared_inbox_url,
matrix_user_id,
admin,
+ bot_account,
)
}
}
actor_id: inserted_person.actor_id.to_owned(),
bio: None,
local: true,
+ bot_account: false,
admin: false,
private_key: None,
public_key: None,
show_avatars -> Bool,
send_notifications_to_email -> Bool,
validator_time -> Timestamp,
+ show_bot_accounts -> Bool,
show_scores -> Bool,
}
}
shared_inbox_url -> Nullable<Varchar>,
matrix_user_id -> Nullable<Text>,
admin -> Bool,
+ bot_account -> Bool,
}
}
shared_inbox_url -> Nullable<Varchar>,
matrix_user_id -> Nullable<Text>,
admin -> Bool,
+ bot_account -> Bool,
}
}
shared_inbox_url -> Nullable<Varchar>,
matrix_user_id -> Nullable<Text>,
admin -> Bool,
+ bot_account -> Bool,
}
}
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub validator_time: chrono::NaiveDateTime,
+ pub show_bot_accounts: bool,
pub show_scores: bool,
}
pub lang: Option<String>,
pub show_avatars: Option<bool>,
pub send_notifications_to_email: Option<bool>,
+ pub show_bot_accounts: Option<bool>,
pub show_scores: Option<bool>,
}
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub validator_time: chrono::NaiveDateTime,
+ pub show_bot_accounts: bool,
pub show_scores: bool,
}
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
/// A safe representation of person, without the sensitive info
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>,
pub admin: bool,
+ pub bot_account: bool,
}
#[derive(Insertable, AsChangeset, Clone, Default)]
pub shared_inbox_url: Option<Option<DbUrl>>,
pub matrix_user_id: Option<Option<String>>,
pub admin: Option<bool>,
+ pub bot_account: Option<bool>,
}
search_term: Option<String>,
saved_only: bool,
unread_only: bool,
+ show_bot_accounts: bool,
page: Option<i64>,
limit: Option<i64>,
}
search_term: None,
saved_only: false,
unread_only: false,
+ show_bot_accounts: true,
page: None,
limit: None,
}
self
}
+ pub fn show_bot_accounts(mut self, show_bot_accounts: bool) -> Self {
+ self.show_bot_accounts = show_bot_accounts;
+ self
+ }
+
pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
self.page = page.get_optional();
self
query = query.filter(comment_saved::id.is_not_null());
}
+ if !self.show_bot_accounts {
+ query = query.filter(person::bot_account.eq(false));
+ };
+
query = match self.sort {
SortType::Hot | SortType::Active => query
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
banned: false,
deleted: false,
admin: false,
+ bot_account: false,
bio: None,
banner: None,
updated: None,
search_term: Option<String>,
url_search: Option<String>,
show_nsfw: bool,
+ show_bot_accounts: bool,
saved_only: bool,
unread_only: bool,
page: Option<i64>,
search_term: None,
url_search: None,
show_nsfw: true,
+ show_bot_accounts: true,
saved_only: false,
unread_only: false,
page: None,
self
}
+ pub fn show_bot_accounts(mut self, show_bot_accounts: bool) -> Self {
+ self.show_bot_accounts = show_bot_accounts;
+ self
+ }
+
pub fn saved_only(mut self, saved_only: bool) -> Self {
self.saved_only = saved_only;
self
.filter(community::nsfw.eq(false));
};
+ if !self.show_bot_accounts {
+ query = query.filter(person::bot_account.eq(false));
+ };
+
// TODO These two might be wrong
if self.saved_only {
query = query.filter(post_saved::id.is_not_null());
let person_name = "tegan".to_string();
let community_name = "test_community_3".to_string();
let post_name = "test post 3".to_string();
+ let bot_post_name = "test bot post".to_string();
let new_person = PersonForm {
name: person_name.to_owned(),
let inserted_person = Person::create(&conn, &new_person).unwrap();
+ let new_bot = PersonForm {
+ name: person_name.to_owned(),
+ bot_account: Some(true),
+ ..PersonForm::default()
+ };
+
+ let inserted_bot = Person::create(&conn, &new_bot).unwrap();
+
let new_community = CommunityForm {
name: community_name.to_owned(),
title: "nada".to_owned(),
let inserted_post = Post::create(&conn, &new_post).unwrap();
+ let new_bot_post = PostForm {
+ name: bot_post_name,
+ creator_id: inserted_bot.id,
+ community_id: inserted_community.id,
+ ..PostForm::default()
+ };
+
+ let _inserted_bot_post = Post::create(&conn, &new_bot_post).unwrap();
+
let post_like_form = PostLikeForm {
post_id: inserted_post.id,
person_id: inserted_person.id,
let read_post_listings_with_person = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::Community)
.sort(&SortType::New)
+ .show_bot_accounts(false)
.community_id(inserted_community.id)
.my_person_id(inserted_person.id)
.list()
actor_id: inserted_person.actor_id.to_owned(),
local: true,
admin: false,
+ bot_account: false,
banned: false,
deleted: false,
bio: None,
let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
Community::delete(&conn, inserted_community.id).unwrap();
Person::delete(&conn, inserted_person.id).unwrap();
+ Person::delete(&conn, inserted_bot.id).unwrap();
// The with user
assert_eq!(
expected_post_listing_with_user,
read_post_listing_with_person
);
+
+ // Should be only one person, IE the bot post should be missing
assert_eq!(1, read_post_listings_with_person.len());
// Without the user
assert_eq!(
expected_post_listing_no_person,
- read_post_listings_no_person[0]
+ read_post_listings_no_person[1]
);
assert_eq!(expected_post_listing_no_person, read_post_listing_no_person);
- assert_eq!(1, read_post_listings_no_person.len());
- // assert_eq!(expected_post, inserted_post);
- // assert_eq!(expected_post, updated_post);
+ // Should be 2 posts, with the bot post
+ assert_eq!(2, read_post_listings_no_person.len());
+
assert_eq!(expected_post_like, inserted_post_like);
assert_eq!(1, like_removed);
assert_eq!(1, num_deleted);
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(&conn)?;
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
- let person_id = LocalUser::read(&conn, local_user_id)?.person_id;
+ let local_user = LocalUser::read(&conn, local_user_id)?;
+ let person_id = local_user.person_id;
+ let show_bot_accounts = local_user.show_bot_accounts;
let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::Subscribed)
.my_person_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.sort(sort_type)
.list()?;
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(&conn)?;
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
- let person_id = LocalUser::read(&conn, local_user_id)?.person_id;
+ let local_user = LocalUser::read(&conn, local_user_id)?;
+ let person_id = local_user.person_id;
+ let show_bot_accounts = local_user.show_bot_accounts;
let sort = SortType::New;
let replies = CommentQueryBuilder::create(&conn)
.recipient_id(person_id)
.my_person_id(person_id)
+ .show_bot_accounts(show_bot_accounts)
.sort(&sort)
.list()?;
--- /dev/null
+drop view person_alias_1, person_alias_2;
+alter table person drop column bot_account;
+create view person_alias_1 as select * from person;
+create view person_alias_2 as select * from person;
+
+alter table local_user drop column show_bot_accounts;
--- /dev/null
+-- Add the bot_account column to the person table
+drop view person_alias_1, person_alias_2;
+alter table person add column bot_account boolean not null default false;
+create view person_alias_1 as select * from person;
+create view person_alias_2 as select * from person;
+
+-- Add the show_bot_accounts to the local user table as a setting
+alter table local_user add column show_bot_accounts boolean not null default true;