Merge branch 'main' into feature/mark_post_as_read

This commit is contained in:
Dessalines 2021-04-26 10:44:19 -04:00
commit 880c51687a
31 changed files with 343 additions and 329 deletions

View file

@ -8,11 +8,12 @@ platform:
steps: steps:
- name: chown repo - name: prepare repo
image: ekidd/rust-musl-builder:1.50.0 image: ekidd/rust-musl-builder:1.50.0
user: root user: root
commands: commands:
- chown 1000:1000 . -R - chown 1000:1000 . -R
- git fetch --tags
- name: check formatting - name: check formatting
image: rustdocker/rust:nightly image: rustdocker/rust:nightly
@ -34,7 +35,7 @@ steps:
RUST_TEST_THREADS: 1 RUST_TEST_THREADS: 1
commands: commands:
- sudo apt-get update - sudo apt-get update
- sudo apt-get -y install --no-install-recommends espeak postgresql-client - sudo apt-get -y install --no-install-recommends postgresql-client
- cargo test --workspace --no-fail-fast - cargo test --workspace --no-fail-fast
- name: cargo build - name: cargo build
@ -136,6 +137,15 @@ platform:
steps: steps:
- name: prepare repo
image: rust:1.50-slim-buster
user: root
commands:
- chown 1000:1000 . -R
- apt update
- apt install --no-install-recommends --yes git
- git fetch --tags
- name: cargo test - name: cargo test
image: rust:1.50-slim-buster image: rust:1.50-slim-buster
environment: environment:
@ -145,7 +155,7 @@ steps:
RUST_TEST_THREADS: 1 RUST_TEST_THREADS: 1
commands: commands:
- apt-get update - apt-get update
- apt-get -y install --no-install-recommends espeak postgresql-client libssl-dev pkg-config libpq-dev - apt-get -y install --no-install-recommends postgresql-client libssl-dev pkg-config libpq-dev
- cargo test --workspace --no-fail-fast - cargo test --workspace --no-fail-fast
- cargo build - cargo build

View file

@ -171,7 +171,7 @@ impl Perform for BanFromCommunity {
} }
// Remove/Restore their data if that's desired // Remove/Restore their data if that's desired
if data.remove_data { if data.remove_data.unwrap_or(false) {
// Posts // Posts
blocking(context.pool(), move |conn: &'_ _| { blocking(context.pool(), move |conn: &'_ _| {
Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true) Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)

View file

@ -16,6 +16,7 @@ use lemmy_api_common::{
use lemmy_db_queries::{ use lemmy_db_queries::{
diesel_option_overwrite, diesel_option_overwrite,
diesel_option_overwrite_to_url, diesel_option_overwrite_to_url,
from_opt_str_to_opt_enum,
source::{ source::{
comment::Comment_, comment::Comment_,
local_user::LocalUser_, local_user::LocalUser_,
@ -68,7 +69,6 @@ use lemmy_websocket::{
LemmyContext, LemmyContext,
UserOperation, UserOperation,
}; };
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for Login { impl Perform for Login {
@ -398,7 +398,7 @@ impl Perform for BanPerson {
} }
// Remove their data if that's desired // Remove their data if that's desired
if data.remove_data { if data.remove_data.unwrap_or(false) {
// Posts // Posts
blocking(context.pool(), move |conn: &'_ _| { blocking(context.pool(), move |conn: &'_ _| {
Post::update_removed_for_creator(conn, banned_person_id, None, true) Post::update_removed_for_creator(conn, banned_person_id, None, true)
@ -463,7 +463,7 @@ impl Perform for GetReplies {
let data: &GetReplies = &self; let data: &GetReplies = &self;
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
let sort = SortType::from_str(&data.sort)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
@ -473,7 +473,7 @@ impl Perform for GetReplies {
let replies = blocking(context.pool(), move |conn| { let replies = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn) CommentQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.unread_only(unread_only) .unread_only(unread_only)
.recipient_id(person_id) .recipient_id(person_id)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
@ -500,7 +500,7 @@ impl Perform for GetPersonMentions {
let data: &GetPersonMentions = &self; let data: &GetPersonMentions = &self;
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
let sort = SortType::from_str(&data.sort)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
@ -510,7 +510,7 @@ impl Perform for GetPersonMentions {
PersonMentionQueryBuilder::create(conn) PersonMentionQueryBuilder::create(conn)
.recipient_id(person_id) .recipient_id(person_id)
.my_person_id(person_id) .my_person_id(person_id)
.sort(&sort) .sort(sort)
.unread_only(unread_only) .unread_only(unread_only)
.page(page) .page(page)
.limit(limit) .limit(limit)

View file

@ -9,12 +9,16 @@ use lemmy_api_common::{
get_local_user_view_from_jwt_opt, get_local_user_view_from_jwt_opt,
is_admin, is_admin,
site::*, site::*,
user_show_bot_accounts,
user_show_nsfw,
user_show_read_posts,
}; };
use lemmy_apub::fetcher::search::search_by_apub_id; use lemmy_apub::fetcher::search::search_by_apub_id;
use lemmy_db_queries::{source::site::Site_, Crud, SearchType, SortType}; use lemmy_db_queries::{
from_opt_str_to_opt_enum,
source::site::Site_,
Crud,
ListingType,
SearchType,
SortType,
};
use lemmy_db_schema::source::{moderator::*, site::Site}; use lemmy_db_schema::source::{moderator::*, site::Site};
use lemmy_db_views::{ use lemmy_db_views::{
comment_view::CommentQueryBuilder, comment_view::CommentQueryBuilder,
@ -46,7 +50,6 @@ use lemmy_utils::{
}; };
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use log::debug; use log::debug;
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for GetModlog { impl Perform for GetModlog {
@ -140,14 +143,16 @@ impl Perform for Search {
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; 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_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = user_show_bot_accounts(&local_user_view); let show_bot_accounts = local_user_view
let show_read_posts = user_show_read_posts(&local_user_view); .as_ref()
.map(|t| t.local_user.show_bot_accounts);
let show_read_posts = local_user_view
.as_ref()
.map(|t| t.local_user.show_read_posts);
let person_id = local_user_view.map(|u| u.person.id); let person_id = local_user_view.map(|u| u.person.id);
let type_ = SearchType::from_str(&data.type_)?;
let mut posts = Vec::new(); let mut posts = Vec::new();
let mut comments = Vec::new(); let mut comments = Vec::new();
let mut communities = Vec::new(); let mut communities = Vec::new();
@ -158,19 +163,24 @@ impl Perform for Search {
let q = data.q.to_owned(); let q = data.q.to_owned();
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let sort = SortType::from_str(&data.sort)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.listing_type);
let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All);
let community_id = data.community_id; let community_id = data.community_id;
let community_name = data.community_name.to_owned(); let community_name = data.community_name.to_owned();
match type_ { let creator_id = data.creator_id;
match search_type {
SearchType::Posts => { SearchType::Posts => {
posts = blocking(context.pool(), move |conn| { posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn) PostQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.listing_type(listing_type)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_name(community_name)
.creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.search_term(q) .search_term(q)
.page(page) .page(page)
@ -182,9 +192,13 @@ impl Perform for Search {
SearchType::Comments => { SearchType::Comments => {
comments = blocking(context.pool(), move |conn| { comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(&conn) CommentQueryBuilder::create(&conn)
.sort(&sort) .sort(sort)
.listing_type(listing_type)
.search_term(q) .search_term(q)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.community_id(community_id)
.community_name(community_name)
.creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
.limit(limit) .limit(limit)
@ -195,7 +209,8 @@ impl Perform for Search {
SearchType::Communities => { SearchType::Communities => {
communities = blocking(context.pool(), move |conn| { communities = blocking(context.pool(), move |conn| {
CommunityQueryBuilder::create(conn) CommunityQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.listing_type(listing_type)
.search_term(q) .search_term(q)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
@ -207,7 +222,7 @@ impl Perform for Search {
SearchType::Users => { SearchType::Users => {
users = blocking(context.pool(), move |conn| { users = blocking(context.pool(), move |conn| {
PersonQueryBuilder::create(conn) PersonQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.search_term(q) .search_term(q)
.page(page) .page(page)
.limit(limit) .limit(limit)
@ -216,14 +231,20 @@ impl Perform for Search {
.await??; .await??;
} }
SearchType::All => { SearchType::All => {
// If the community or creator is included, dont search communities or users
let community_or_creator_included =
data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
posts = blocking(context.pool(), move |conn| { posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn) PostQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.listing_type(listing_type)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_name(community_name)
.creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.search_term(q) .search_term(q)
.page(page) .page(page)
@ -233,13 +254,17 @@ impl Perform for Search {
.await??; .await??;
let q = data.q.to_owned(); let q = data.q.to_owned();
let sort = SortType::from_str(&data.sort)?; let community_name = data.community_name.to_owned();
comments = blocking(context.pool(), move |conn| { comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn) CommentQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.listing_type(listing_type)
.search_term(q) .search_term(q)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.community_id(community_id)
.community_name(community_name)
.creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
.limit(limit) .limit(limit)
@ -248,42 +273,51 @@ impl Perform for Search {
.await??; .await??;
let q = data.q.to_owned(); let q = data.q.to_owned();
let sort = SortType::from_str(&data.sort)?;
communities = blocking(context.pool(), move |conn| { communities = if community_or_creator_included {
vec![]
} else {
blocking(context.pool(), move |conn| {
CommunityQueryBuilder::create(conn) CommunityQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.listing_type(listing_type)
.search_term(q) .search_term(q)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
.limit(limit) .limit(limit)
.list() .list()
}) })
.await??; .await??
};
let q = data.q.to_owned(); let q = data.q.to_owned();
let sort = SortType::from_str(&data.sort)?;
users = blocking(context.pool(), move |conn| { users = if community_or_creator_included {
vec![]
} else {
blocking(context.pool(), move |conn| {
PersonQueryBuilder::create(conn) PersonQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.search_term(q) .search_term(q)
.page(page) .page(page)
.limit(limit) .limit(limit)
.list() .list()
}) })
.await??; .await??
};
} }
SearchType::Url => { SearchType::Url => {
posts = blocking(context.pool(), move |conn| { posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn) PostQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.listing_type(listing_type)
.my_person_id(person_id) .my_person_id(person_id)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_name(community_name)
.creator_id(creator_id)
.url_search(q) .url_search(q)
.page(page) .page(page)
.limit(limit) .limit(limit)
@ -295,7 +329,7 @@ impl Perform for Search {
// Return the jwt // Return the jwt
Ok(SearchResponse { Ok(SearchResponse {
type_: data.type_.to_owned(), type_: search_type.to_string(),
comments, comments,
posts, posts,
communities, communities,

View file

@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct CreateComment { pub struct CreateComment {
pub content: String, pub content: String,
pub parent_id: Option<CommentId>,
pub post_id: PostId, pub post_id: PostId,
pub parent_id: Option<CommentId>,
pub form_id: Option<String>, pub form_id: Option<String>,
pub auth: String, pub auth: String,
} }
@ -64,13 +64,13 @@ pub struct CreateCommentLike {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetComments { pub struct GetComments {
pub type_: String, pub type_: Option<String>,
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub community_name: Option<String>, pub community_name: Option<String>,
pub saved_only: bool, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<String>,
} }

View file

@ -39,8 +39,8 @@ pub struct CommunityResponse {
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct ListCommunities { pub struct ListCommunities {
pub type_: String, pub type_: Option<String>,
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: Option<String>, pub auth: Option<String>,
@ -56,7 +56,7 @@ pub struct BanFromCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
pub ban: bool, pub ban: bool,
pub remove_data: bool, pub remove_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
pub expires: Option<i64>, pub expires: Option<i64>,
pub auth: String, pub auth: String,
@ -84,7 +84,7 @@ pub struct AddModToCommunityResponse {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct EditCommunity { pub struct EditCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub title: String, pub title: Option<String>,
pub description: Option<String>, pub description: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,

View file

@ -237,30 +237,6 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
Ok(()) 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,
}
}
/// A helper method for showing read posts
pub fn user_show_read_posts(local_user_view: &Option<LocalUserView>) -> bool {
match local_user_view {
Some(uv) => uv.to_owned().local_user.show_read_posts,
None => true,
}
}
pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> { pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> {
blocking(pool, move |conn| Post::read(conn, post_id)) blocking(pool, move |conn| Post::read(conn, post_id))
.await? .await?

View file

@ -21,10 +21,10 @@ use lemmy_db_schema::{CommunityId, PersonId, PersonMentionId, PrivateMessageId};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Register { pub struct Register {
pub username: String, pub username: String,
pub email: Option<String>,
pub password: String, pub password: String,
pub password_verify: String, pub password_verify: String,
pub show_nsfw: bool, pub show_nsfw: bool,
pub email: Option<String>,
pub captcha_uuid: Option<String>, pub captcha_uuid: Option<String>,
pub captcha_answer: Option<String>, pub captcha_answer: Option<String>,
} }
@ -81,13 +81,13 @@ pub struct LoginResponse {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetPersonDetails { pub struct GetPersonDetails {
pub person_id: Option<PersonId>, pub person_id: Option<PersonId>, // One of these two are required
pub username: Option<String>, pub username: Option<String>,
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub saved_only: bool, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<String>,
} }
@ -131,7 +131,7 @@ pub struct AddAdminResponse {
pub struct BanPerson { pub struct BanPerson {
pub person_id: PersonId, pub person_id: PersonId,
pub ban: bool, pub ban: bool,
pub remove_data: bool, pub remove_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
pub expires: Option<i64>, pub expires: Option<i64>,
pub auth: String, pub auth: String,
@ -145,19 +145,19 @@ pub struct BanPersonResponse {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetReplies { pub struct GetReplies {
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub unread_only: bool, pub unread_only: Option<bool>,
pub auth: String, pub auth: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetPersonMentions { pub struct GetPersonMentions {
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub unread_only: bool, pub unread_only: Option<bool>,
pub auth: String, pub auth: String,
} }
@ -224,7 +224,7 @@ pub struct MarkPrivateMessageAsRead {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetPrivateMessages { pub struct GetPrivateMessages {
pub unread_only: bool, pub unread_only: Option<bool>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: String, pub auth: String,

View file

@ -14,10 +14,10 @@ use url::Url;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct CreatePost { pub struct CreatePost {
pub name: String, pub name: String,
pub community_id: CommunityId,
pub url: Option<Url>, pub url: Option<Url>,
pub body: Option<String>, pub body: Option<String>,
pub nsfw: bool, pub nsfw: Option<bool>,
pub community_id: CommunityId,
pub auth: String, pub auth: String,
} }
@ -43,13 +43,13 @@ pub struct GetPostResponse {
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct GetPosts { pub struct GetPosts {
pub type_: String, pub type_: Option<String>,
pub sort: String, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub community_name: Option<String>, pub community_name: Option<String>,
pub saved_only: bool, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<String>,
} }
@ -68,10 +68,10 @@ pub struct CreatePostLike {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct EditPost { pub struct EditPost {
pub post_id: PostId, pub post_id: PostId,
pub name: String, pub name: Option<String>,
pub url: Option<Url>, pub url: Option<Url>,
pub body: Option<String>, pub body: Option<String>,
pub nsfw: bool, pub nsfw: Option<bool>,
pub auth: String, pub auth: String,
} }

View file

@ -22,10 +22,12 @@ use serde::{Deserialize, Serialize};
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct Search { pub struct Search {
pub q: String, pub q: String,
pub type_: String,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub community_name: Option<String>, pub community_name: Option<String>,
pub sort: String, pub creator_id: Option<PersonId>,
pub type_: Option<String>,
pub sort: Option<String>,
pub listing_type: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: Option<String>, pub auth: Option<String>,
@ -68,23 +70,23 @@ pub struct CreateSite {
pub description: Option<String>, pub description: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,
pub enable_downvotes: bool, pub enable_downvotes: Option<bool>,
pub open_registration: bool, pub open_registration: Option<bool>,
pub enable_nsfw: bool, pub enable_nsfw: Option<bool>,
pub community_creation_admin_only: bool, pub community_creation_admin_only: Option<bool>,
pub auth: String, pub auth: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct EditSite { pub struct EditSite {
pub name: String, pub name: Option<String>,
pub sidebar: Option<String>, pub sidebar: Option<String>,
pub description: Option<String>, pub description: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,
pub enable_downvotes: bool, pub enable_downvotes: Option<bool>,
pub open_registration: bool, pub open_registration: Option<bool>,
pub enable_nsfw: bool, pub enable_nsfw: Option<bool>,
pub community_creation_admin_only: Option<bool>, pub community_creation_admin_only: Option<bool>,
pub auth: String, pub auth: String,
} }

View file

@ -1,16 +1,10 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{ use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt};
blocking, use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
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_db_views::comment_view::CommentQueryBuilder;
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ApiError, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetComments { impl PerformCrud for GetComments {
@ -24,11 +18,13 @@ impl PerformCrud for GetComments {
let data: &GetComments = &self; let data: &GetComments = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; 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 show_bot_accounts = local_user_view
.as_ref()
.map(|t| t.local_user.show_bot_accounts);
let person_id = local_user_view.map(|u| u.person.id); let person_id = local_user_view.map(|u| u.person.id);
let type_ = ListingType::from_str(&data.type_)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let sort = SortType::from_str(&data.sort)?; let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
let community_id = data.community_id; let community_id = data.community_id;
let community_name = data.community_name.to_owned(); let community_name = data.community_name.to_owned();
@ -37,8 +33,8 @@ impl PerformCrud for GetComments {
let limit = data.limit; let limit = data.limit;
let comments = blocking(context.pool(), move |conn| { let comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn) CommentQueryBuilder::create(conn)
.listing_type(type_) .listing_type(listing_type)
.sort(&sort) .sort(sort)
.saved_only(saved_only) .saved_only(saved_only)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_name(community_name)

View file

@ -1,7 +1,12 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt}; use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt};
use lemmy_db_queries::{source::community::Community_, ListingType, SortType}; use lemmy_db_queries::{
from_opt_str_to_opt_enum,
source::community::Community_,
ListingType,
SortType,
};
use lemmy_db_schema::source::community::*; use lemmy_db_schema::source::community::*;
use lemmy_db_views_actor::{ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
@ -9,7 +14,6 @@ use lemmy_db_views_actor::{
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ApiError, ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext}; use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext};
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetCommunity { impl PerformCrud for GetCommunity {
@ -86,15 +90,15 @@ impl PerformCrud for ListCommunities {
None => false, None => false,
}; };
let type_ = ListingType::from_str(&data.type_)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let sort = SortType::from_str(&data.sort)?; let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let communities = blocking(context.pool(), move |conn| { let communities = blocking(context.pool(), move |conn| {
CommunityQueryBuilder::create(conn) CommunityQueryBuilder::create(conn)
.listing_type(&type_) .listing_type(listing_type)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)

View file

@ -16,12 +16,7 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
community_view::CommunityView, community_view::CommunityView,
}; };
use lemmy_utils::{ use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError};
utils::{check_slurs, check_slurs_opt},
ApiError,
ConnectionId,
LemmyError,
};
use lemmy_websocket::{LemmyContext, UserOperationCrud}; use lemmy_websocket::{LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
@ -36,7 +31,7 @@ impl PerformCrud for EditCommunity {
let data: &EditCommunity = &self; let data: &EditCommunity = &self;
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
check_slurs(&data.title)?; check_slurs_opt(&data.title)?;
check_slurs_opt(&data.description)?; check_slurs_opt(&data.description)?;
// Verify its a mod (only mods can edit it) // Verify its a mod (only mods can edit it)
@ -61,7 +56,7 @@ impl PerformCrud for EditCommunity {
let community_form = CommunityForm { let community_form = CommunityForm {
name: read_community.name, name: read_community.name,
title: data.title.to_owned(), title: data.title.to_owned().unwrap_or(read_community.title),
description: data.description.to_owned(), description: data.description.to_owned(),
icon, icon,
banner, banner,

View file

@ -1,15 +1,7 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{ use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, mark_post_as_read, post::*};
blocking, use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
get_local_user_view_from_jwt_opt,
mark_post_as_read,
post::*,
user_show_bot_accounts,
user_show_nsfw,
user_show_read_posts,
};
use lemmy_db_queries::{ListingType, SortType};
use lemmy_db_views::{ use lemmy_db_views::{
comment_view::CommentQueryBuilder, comment_view::CommentQueryBuilder,
post_view::{PostQueryBuilder, PostView}, post_view::{PostQueryBuilder, PostView},
@ -20,7 +12,6 @@ use lemmy_db_views_actor::{
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ApiError, ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext}; use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetPost { impl PerformCrud for GetPost {
@ -34,8 +25,9 @@ impl PerformCrud for GetPost {
let data: &GetPost = &self; let data: &GetPost = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; 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 show_bot_accounts = local_user_view
.as_ref()
.map(|t| t.local_user.show_bot_accounts);
let person_id = local_user_view.map(|u| u.person.id); let person_id = local_user_view.map(|u| u.person.id);
let id = data.id; let id = data.id;
@ -105,12 +97,16 @@ impl PerformCrud for GetPosts {
let person_id = local_user_view.to_owned().map(|l| l.person.id); let person_id = local_user_view.to_owned().map(|l| l.person.id);
let show_nsfw = user_show_nsfw(&local_user_view); let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = user_show_bot_accounts(&local_user_view); let show_bot_accounts = local_user_view
let show_read_posts = user_show_read_posts(&local_user_view); .as_ref()
.map(|t| t.local_user.show_bot_accounts);
let show_read_posts = local_user_view
.as_ref()
.map(|t| t.local_user.show_read_posts);
let type_ = ListingType::from_str(&data.type_)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let sort = SortType::from_str(&data.sort)?; let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
@ -120,8 +116,8 @@ impl PerformCrud for GetPosts {
let posts = blocking(context.pool(), move |conn| { let posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn) PostQueryBuilder::create(conn)
.listing_type(&type_) .listing_type(listing_type)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)

View file

@ -7,7 +7,7 @@ use lemmy_db_schema::{naive_now, source::post::*};
use lemmy_db_views::post_view::PostView; use lemmy_db_views::post_view::PostView;
use lemmy_utils::{ use lemmy_utils::{
request::fetch_iframely_and_pictrs_data, request::fetch_iframely_and_pictrs_data,
utils::{check_slurs, check_slurs_opt, is_valid_post_title}, utils::{check_slurs_opt, is_valid_post_title},
ApiError, ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
@ -26,12 +26,14 @@ impl PerformCrud for EditPost {
let data: &EditPost = &self; let data: &EditPost = &self;
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
check_slurs(&data.name)?; check_slurs_opt(&data.name)?;
check_slurs_opt(&data.body)?; check_slurs_opt(&data.body)?;
if !is_valid_post_title(&data.name) { if let Some(name) = &data.name {
if !is_valid_post_title(name) {
return Err(ApiError::err("invalid_post_title").into()); return Err(ApiError::err("invalid_post_title").into());
} }
}
let post_id = data.post_id; let post_id = data.post_id;
let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
@ -56,7 +58,7 @@ impl PerformCrud for EditPost {
let post_form = PostForm { let post_form = PostForm {
creator_id: orig_post.creator_id.to_owned(), creator_id: orig_post.creator_id.to_owned(),
community_id: orig_post.community_id, community_id: orig_post.community_id,
name: data.name.trim().to_owned(), name: data.name.to_owned().unwrap_or(orig_post.name),
url: data_url.map(|u| u.to_owned().into()), url: data_url.map(|u| u.to_owned().into()),
body: data.body.to_owned(), body: data.body.to_owned(),
nsfw: data.nsfw, nsfw: data.nsfw,

View file

@ -67,7 +67,7 @@ impl PerformCrud for CreateSite {
open_registration: data.open_registration, open_registration: data.open_registration,
enable_nsfw: data.enable_nsfw, enable_nsfw: data.enable_nsfw,
updated: None, updated: None,
community_creation_admin_only: Some(data.community_creation_admin_only), community_creation_admin_only: data.community_creation_admin_only,
}; };
let create_site = move |conn: &'_ _| Site::create(conn, &site_form); let create_site = move |conn: &'_ _| Site::create(conn, &site_form);

View file

@ -47,11 +47,11 @@ impl PerformCrud for GetSite {
description: None, description: None,
icon: None, icon: None,
banner: None, banner: None,
enable_downvotes: true, enable_downvotes: None,
open_registration: true, open_registration: None,
enable_nsfw: true, enable_nsfw: None,
auth: login_response.jwt, auth: login_response.jwt,
community_creation_admin_only: false, community_creation_admin_only: None,
}; };
create_site.perform(context, websocket_id).await?; create_site.perform(context, websocket_id).await?;
info!("Site {} created", setup.site_name); info!("Site {} created", setup.site_name);

View file

@ -18,12 +18,7 @@ use lemmy_db_schema::{
source::site::{Site, SiteForm}, source::site::{Site, SiteForm},
}; };
use lemmy_db_views::site_view::SiteView; use lemmy_db_views::site_view::SiteView;
use lemmy_utils::{ use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError};
utils::{check_slurs, check_slurs_opt},
ApiError,
ConnectionId,
LemmyError,
};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud}; use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
@ -37,7 +32,7 @@ impl PerformCrud for EditSite {
let data: &EditSite = &self; let data: &EditSite = &self;
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
check_slurs(&data.name)?; check_slurs_opt(&data.name)?;
check_slurs_opt(&data.description)?; check_slurs_opt(&data.description)?;
// Make sure user is an admin // Make sure user is an admin
@ -55,12 +50,12 @@ impl PerformCrud for EditSite {
} }
let site_form = SiteForm { let site_form = SiteForm {
name: data.name.to_owned(), creator_id: found_site.creator_id,
name: data.name.to_owned().unwrap_or(found_site.name),
sidebar, sidebar,
description, description,
icon, icon,
banner, banner,
creator_id: found_site.creator_id,
updated: Some(naive_now()), updated: Some(naive_now()),
enable_downvotes: data.enable_downvotes, enable_downvotes: data.enable_downvotes,
open_registration: data.open_registration, open_registration: data.open_registration,

View file

@ -1,14 +1,7 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{ use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*};
blocking, use lemmy_db_queries::{from_opt_str_to_opt_enum, source::person::Person_, SortType};
get_local_user_view_from_jwt_opt,
person::*,
user_show_bot_accounts,
user_show_nsfw,
user_show_read_posts,
};
use lemmy_db_queries::{source::person::Person_, SortType};
use lemmy_db_schema::source::person::*; use lemmy_db_schema::source::person::*;
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder}; use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
use lemmy_db_views_actor::{ use lemmy_db_views_actor::{
@ -18,7 +11,6 @@ use lemmy_db_views_actor::{
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ApiError, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use std::str::FromStr;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetPersonDetails { impl PerformCrud for GetPersonDetails {
@ -32,11 +24,15 @@ impl PerformCrud for GetPersonDetails {
let data: &GetPersonDetails = &self; let data: &GetPersonDetails = &self;
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; 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_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = user_show_bot_accounts(&local_user_view); let show_bot_accounts = local_user_view
let show_read_posts = user_show_read_posts(&local_user_view); .as_ref()
.map(|t| t.local_user.show_bot_accounts);
let show_read_posts = local_user_view
.as_ref()
.map(|t| t.local_user.show_read_posts);
let sort = SortType::from_str(&data.sort)?; let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let username = data let username = data
.username .username
@ -71,7 +67,7 @@ impl PerformCrud for GetPersonDetails {
let (posts, comments) = blocking(context.pool(), move |conn| { let (posts, comments) = blocking(context.pool(), move |conn| {
let mut posts_query = PostQueryBuilder::create(conn) let mut posts_query = PostQueryBuilder::create(conn)
.sort(&sort) .sort(sort)
.show_nsfw(show_nsfw) .show_nsfw(show_nsfw)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
@ -84,7 +80,7 @@ impl PerformCrud for GetPersonDetails {
let mut comments_query = CommentQueryBuilder::create(conn) let mut comments_query = CommentQueryBuilder::create(conn)
.my_person_id(person_id) .my_person_id(person_id)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.sort(&sort) .sort(sort)
.saved_only(saved_only) .saved_only(saved_only)
.community_id(community_id) .community_id(community_id)
.page(page) .page(page)
@ -92,7 +88,7 @@ impl PerformCrud for GetPersonDetails {
// If its saved only, you don't care what creator it was // If its saved only, you don't care what creator it was
// Or, if its not saved, then you only want it for that specific creator // Or, if its not saved, then you only want it for that specific creator
if !saved_only { if !saved_only.unwrap_or(false) {
posts_query = posts_query.creator_id(person_details_id); posts_query = posts_query.creator_id(person_details_id);
comments_query = comments_query.creator_id(person_details_id); comments_query = comments_query.creator_id(person_details_id);
} }

View file

@ -230,8 +230,8 @@ impl FromApubToForm<PageExt> for PostForm {
.as_ref() .as_ref()
.map(|u| u.to_owned().naive_local()), .map(|u| u.to_owned().naive_local()),
deleted: None, deleted: None,
nsfw: ext.sensitive.unwrap_or(false), nsfw: ext.sensitive,
stickied: ext.stickied.or(Some(false)), stickied: ext.stickied,
embed_title: iframely_title, embed_title: iframely_title,
embed_description: iframely_description, embed_description: iframely_description,
embed_html: iframely_html, embed_html: iframely_html,

View file

@ -49,14 +49,14 @@ mod tests {
let site_form = SiteForm { let site_form = SiteForm {
name: "test_site".into(), name: "test_site".into(),
creator_id: inserted_person.id,
sidebar: None, sidebar: None,
description: None, description: None,
icon: None, icon: None,
banner: None, banner: None,
creator_id: inserted_person.id, enable_downvotes: None,
enable_downvotes: true, open_registration: None,
open_registration: true, enable_nsfw: None,
enable_nsfw: true,
updated: None, updated: None,
community_creation_admin_only: Some(false), community_creation_admin_only: Some(false),
}; };

View file

@ -163,7 +163,7 @@ pub fn get_database_url_from_env() -> Result<String, VarError> {
env::var("LEMMY_DATABASE_URL") env::var("LEMMY_DATABASE_URL")
} }
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum SortType { pub enum SortType {
Active, Active,
Hot, Hot,
@ -177,7 +177,7 @@ pub enum SortType {
NewComments, NewComments,
} }
#[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum ListingType { pub enum ListingType {
All, All,
Local, Local,
@ -185,7 +185,7 @@ pub enum ListingType {
Community, Community,
} }
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum SearchType { pub enum SearchType {
All, All,
Comments, Comments,
@ -195,6 +195,10 @@ pub enum SearchType {
Url, Url,
} }
pub fn from_opt_str_to_opt_enum<T: std::str::FromStr>(opt: &Option<String>) -> Option<T> {
opt.as_ref().map(|t| T::from_str(t).ok()).flatten()
}
pub fn fuzzy_search(q: &str) -> String { pub fn fuzzy_search(q: &str) -> String {
let replaced = q.replace(" ", "%"); let replaced = q.replace(" ", "%");
format!("%{}%", replaced) format!("%{}%", replaced)

View file

@ -37,7 +37,7 @@ pub struct PostForm {
pub name: String, pub name: String,
pub creator_id: PersonId, pub creator_id: PersonId,
pub community_id: CommunityId, pub community_id: CommunityId,
pub nsfw: bool, pub nsfw: Option<bool>,
pub url: Option<DbUrl>, pub url: Option<DbUrl>,
pub body: Option<String>, pub body: Option<String>,
pub removed: Option<bool>, pub removed: Option<bool>,

View file

@ -23,12 +23,12 @@ pub struct Site {
#[table_name = "site"] #[table_name = "site"]
pub struct SiteForm { pub struct SiteForm {
pub name: String, pub name: String,
pub sidebar: Option<Option<String>>,
pub creator_id: PersonId, pub creator_id: PersonId,
pub sidebar: Option<Option<String>>,
pub updated: Option<chrono::NaiveDateTime>, pub updated: Option<chrono::NaiveDateTime>,
pub enable_downvotes: bool, pub enable_downvotes: Option<bool>,
pub open_registration: bool, pub open_registration: Option<bool>,
pub enable_nsfw: bool, pub enable_nsfw: Option<bool>,
// when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column. // when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column.
pub icon: Option<Option<DbUrl>>, pub icon: Option<Option<DbUrl>>,
pub banner: Option<Option<DbUrl>>, pub banner: Option<Option<DbUrl>>,

View file

@ -172,8 +172,8 @@ impl CommentView {
pub struct CommentQueryBuilder<'a> { pub struct CommentQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
listing_type: ListingType, listing_type: Option<ListingType>,
sort: &'a SortType, sort: Option<SortType>,
community_id: Option<CommunityId>, community_id: Option<CommunityId>,
community_name: Option<String>, community_name: Option<String>,
post_id: Option<PostId>, post_id: Option<PostId>,
@ -181,9 +181,9 @@ pub struct CommentQueryBuilder<'a> {
recipient_id: Option<PersonId>, recipient_id: Option<PersonId>,
my_person_id: Option<PersonId>, my_person_id: Option<PersonId>,
search_term: Option<String>, search_term: Option<String>,
saved_only: bool, saved_only: Option<bool>,
unread_only: bool, unread_only: Option<bool>,
show_bot_accounts: bool, show_bot_accounts: Option<bool>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
} }
@ -192,8 +192,8 @@ impl<'a> CommentQueryBuilder<'a> {
pub fn create(conn: &'a PgConnection) -> Self { pub fn create(conn: &'a PgConnection) -> Self {
CommentQueryBuilder { CommentQueryBuilder {
conn, conn,
listing_type: ListingType::All, listing_type: None,
sort: &SortType::New, sort: None,
community_id: None, community_id: None,
community_name: None, community_name: None,
post_id: None, post_id: None,
@ -201,21 +201,21 @@ impl<'a> CommentQueryBuilder<'a> {
recipient_id: None, recipient_id: None,
my_person_id: None, my_person_id: None,
search_term: None, search_term: None,
saved_only: false, saved_only: None,
unread_only: false, unread_only: None,
show_bot_accounts: true, show_bot_accounts: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn listing_type(mut self, listing_type: ListingType) -> Self { pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
self.listing_type = listing_type; self.listing_type = listing_type.get_optional();
self self
} }
pub fn sort(mut self, sort: &'a SortType) -> Self { pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
self.sort = sort; self.sort = sort.get_optional();
self self
} }
@ -254,18 +254,18 @@ impl<'a> CommentQueryBuilder<'a> {
self self
} }
pub fn saved_only(mut self, saved_only: bool) -> Self { pub fn saved_only<T: MaybeOptional<bool>>(mut self, saved_only: T) -> Self {
self.saved_only = saved_only; self.saved_only = saved_only.get_optional();
self self
} }
pub fn unread_only(mut self, unread_only: bool) -> Self { pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
self.unread_only = unread_only; self.unread_only = unread_only.get_optional();
self self
} }
pub fn show_bot_accounts(mut self, show_bot_accounts: bool) -> Self { pub fn show_bot_accounts<T: MaybeOptional<bool>>(mut self, show_bot_accounts: T) -> Self {
self.show_bot_accounts = show_bot_accounts; self.show_bot_accounts = show_bot_accounts.get_optional();
self self
} }
@ -350,7 +350,7 @@ impl<'a> CommentQueryBuilder<'a> {
.filter(comment::removed.eq(false)); .filter(comment::removed.eq(false));
} }
if self.unread_only { if self.unread_only.unwrap_or(false) {
query = query.filter(comment::read.eq(false)); query = query.filter(comment::read.eq(false));
} }
@ -376,22 +376,23 @@ impl<'a> CommentQueryBuilder<'a> {
query = query.filter(comment::content.ilike(fuzzy_search(&search_term))); query = query.filter(comment::content.ilike(fuzzy_search(&search_term)));
}; };
query = match self.listing_type { if let Some(listing_type) = self.listing_type {
// ListingType::Subscribed => query.filter(community_follower::subscribed.eq(true)), query = match listing_type {
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)), ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
ListingType::Local => query.filter(community::local.eq(true)), ListingType::Local => query.filter(community::local.eq(true)),
_ => query, _ => query,
}; };
}
if self.saved_only { if self.saved_only.unwrap_or(false) {
query = query.filter(comment_saved::id.is_not_null()); query = query.filter(comment_saved::id.is_not_null());
} }
if !self.show_bot_accounts { if !self.show_bot_accounts.unwrap_or(true) {
query = query.filter(person::bot_account.eq(false)); query = query.filter(person::bot_account.eq(false));
}; };
query = match self.sort { query = match self.sort.unwrap_or(SortType::New) {
SortType::Hot | SortType::Active => query SortType::Hot | SortType::Active => query
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc()) .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
.then_order_by(comment_aggregates::published.desc()), .then_order_by(comment_aggregates::published.desc()),

View file

@ -155,18 +155,18 @@ impl PostView {
pub struct PostQueryBuilder<'a> { pub struct PostQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
listing_type: &'a ListingType, listing_type: Option<ListingType>,
sort: &'a SortType, sort: Option<SortType>,
creator_id: Option<PersonId>, creator_id: Option<PersonId>,
community_id: Option<CommunityId>, community_id: Option<CommunityId>,
community_name: Option<String>, community_name: Option<String>,
my_person_id: Option<PersonId>, my_person_id: Option<PersonId>,
search_term: Option<String>, search_term: Option<String>,
url_search: Option<String>, url_search: Option<String>,
show_nsfw: bool, show_nsfw: Option<bool>,
show_bot_accounts: bool, show_bot_accounts: Option<bool>,
show_read_posts: bool, show_read_posts: Option<bool>,
saved_only: bool, saved_only: Option<bool>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
} }
@ -175,30 +175,30 @@ impl<'a> PostQueryBuilder<'a> {
pub fn create(conn: &'a PgConnection) -> Self { pub fn create(conn: &'a PgConnection) -> Self {
PostQueryBuilder { PostQueryBuilder {
conn, conn,
listing_type: &ListingType::All, listing_type: None,
sort: &SortType::Hot, sort: None,
creator_id: None, creator_id: None,
community_id: None, community_id: None,
community_name: None, community_name: None,
my_person_id: None, my_person_id: None,
search_term: None, search_term: None,
url_search: None, url_search: None,
show_nsfw: true, show_nsfw: None,
show_bot_accounts: true, show_bot_accounts: None,
show_read_posts: true, show_read_posts: None,
saved_only: false, saved_only: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn listing_type(mut self, listing_type: &'a ListingType) -> Self { pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
self.listing_type = listing_type; self.listing_type = listing_type.get_optional();
self self
} }
pub fn sort(mut self, sort: &'a SortType) -> Self { pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
self.sort = sort; self.sort = sort.get_optional();
self self
} }
@ -232,23 +232,23 @@ impl<'a> PostQueryBuilder<'a> {
self self
} }
pub fn show_nsfw(mut self, show_nsfw: bool) -> Self { pub fn show_nsfw<T: MaybeOptional<bool>>(mut self, show_nsfw: T) -> Self {
self.show_nsfw = show_nsfw; self.show_nsfw = show_nsfw.get_optional();
self self
} }
pub fn show_bot_accounts(mut self, show_bot_accounts: bool) -> Self { pub fn show_bot_accounts<T: MaybeOptional<bool>>(mut self, show_bot_accounts: T) -> Self {
self.show_bot_accounts = show_bot_accounts; self.show_bot_accounts = show_bot_accounts.get_optional();
self self
} }
pub fn show_read_posts(mut self, show_read_posts: bool) -> Self { pub fn show_read_posts<T: MaybeOptional<bool>>(mut self, show_read_posts: T) -> Self {
self.show_read_posts = show_read_posts; self.show_read_posts = show_read_posts.get_optional();
self self
} }
pub fn saved_only(mut self, saved_only: bool) -> Self { pub fn saved_only<T: MaybeOptional<bool>>(mut self, saved_only: T) -> Self {
self.saved_only = saved_only; self.saved_only = saved_only.get_optional();
self self
} }
@ -320,11 +320,13 @@ impl<'a> PostQueryBuilder<'a> {
)) ))
.into_boxed(); .into_boxed();
query = match self.listing_type { if let Some(listing_type) = self.listing_type {
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)), query = match listing_type {
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()),
ListingType::Local => query.filter(community::local.eq(true)), ListingType::Local => query.filter(community::local.eq(true)),
_ => query, _ => query,
}; };
}
if let Some(community_id) = self.community_id { if let Some(community_id) = self.community_id {
query = query query = query
@ -357,25 +359,25 @@ impl<'a> PostQueryBuilder<'a> {
query = query.filter(post::creator_id.eq(creator_id)); query = query.filter(post::creator_id.eq(creator_id));
} }
if !self.show_nsfw { if !self.show_nsfw.unwrap_or(true) {
query = query query = query
.filter(post::nsfw.eq(false)) .filter(post::nsfw.eq(false))
.filter(community::nsfw.eq(false)); .filter(community::nsfw.eq(false));
}; };
if !self.show_bot_accounts { if !self.show_bot_accounts.unwrap_or(true) {
query = query.filter(person::bot_account.eq(false)); query = query.filter(person::bot_account.eq(false));
}; };
if self.saved_only { if !self.show_read_posts.unwrap_or(true) {
query = query.filter(post_saved::id.is_not_null());
};
if !self.show_read_posts {
query = query.filter(post_read::id.is_null()); query = query.filter(post_read::id.is_null());
}; };
query = match self.sort { if self.saved_only.unwrap_or(false) {
query = query.filter(post_saved::id.is_not_null());
};
query = match self.sort.unwrap_or(SortType::Hot) {
SortType::Active => query SortType::Active => query
.then_order_by( .then_order_by(
hot_rank( hot_rank(
@ -526,8 +528,8 @@ mod tests {
}; };
let read_post_listings_with_person = PostQueryBuilder::create(&conn) let read_post_listings_with_person = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::Community) .listing_type(ListingType::Community)
.sort(&SortType::New) .sort(SortType::New)
.show_bot_accounts(false) .show_bot_accounts(false)
.community_id(inserted_community.id) .community_id(inserted_community.id)
.my_person_id(inserted_person.id) .my_person_id(inserted_person.id)
@ -535,8 +537,8 @@ mod tests {
.unwrap(); .unwrap();
let read_post_listings_no_person = PostQueryBuilder::create(&conn) let read_post_listings_no_person = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::Community) .listing_type(ListingType::Community)
.sort(&SortType::New) .sort(SortType::New)
.community_id(inserted_community.id) .community_id(inserted_community.id)
.list() .list()
.unwrap(); .unwrap();

View file

@ -46,7 +46,7 @@ impl PrivateMessageView {
pub struct PrivateMessageQueryBuilder<'a> { pub struct PrivateMessageQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
recipient_id: PersonId, recipient_id: PersonId,
unread_only: bool, unread_only: Option<bool>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
} }
@ -56,14 +56,14 @@ impl<'a> PrivateMessageQueryBuilder<'a> {
PrivateMessageQueryBuilder { PrivateMessageQueryBuilder {
conn, conn,
recipient_id, recipient_id,
unread_only: false, unread_only: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn unread_only(mut self, unread_only: bool) -> Self { pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
self.unread_only = unread_only; self.unread_only = unread_only.get_optional();
self self
} }
@ -89,7 +89,7 @@ impl<'a> PrivateMessageQueryBuilder<'a> {
.into_boxed(); .into_boxed();
// If its unread, I only want the ones to me // If its unread, I only want the ones to me
if self.unread_only { if self.unread_only.unwrap_or(false) {
query = query query = query
.filter(private_message::read.eq(false)) .filter(private_message::read.eq(false))
.filter(private_message::recipient_id.eq(self.recipient_id)); .filter(private_message::recipient_id.eq(self.recipient_id));

View file

@ -94,10 +94,10 @@ impl CommunityView {
pub struct CommunityQueryBuilder<'a> { pub struct CommunityQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
listing_type: &'a ListingType, listing_type: Option<ListingType>,
sort: &'a SortType, sort: Option<SortType>,
my_person_id: Option<PersonId>, my_person_id: Option<PersonId>,
show_nsfw: bool, show_nsfw: Option<bool>,
search_term: Option<String>, search_term: Option<String>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
@ -108,27 +108,27 @@ impl<'a> CommunityQueryBuilder<'a> {
CommunityQueryBuilder { CommunityQueryBuilder {
conn, conn,
my_person_id: None, my_person_id: None,
listing_type: &ListingType::All, listing_type: None,
sort: &SortType::Hot, sort: None,
show_nsfw: true, show_nsfw: None,
search_term: None, search_term: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn listing_type(mut self, listing_type: &'a ListingType) -> Self { pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
self.listing_type = listing_type; self.listing_type = listing_type.get_optional();
self self
} }
pub fn sort(mut self, sort: &'a SortType) -> Self { pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
self.sort = sort; self.sort = sort.get_optional();
self self
} }
pub fn show_nsfw(mut self, show_nsfw: bool) -> Self { pub fn show_nsfw<T: MaybeOptional<bool>>(mut self, show_nsfw: T) -> Self {
self.show_nsfw = show_nsfw; self.show_nsfw = show_nsfw.get_optional();
self self
} }
@ -180,7 +180,7 @@ impl<'a> CommunityQueryBuilder<'a> {
.or_filter(community::description.ilike(searcher)); .or_filter(community::description.ilike(searcher));
}; };
match self.sort { match self.sort.unwrap_or(SortType::Hot) {
SortType::New => query = query.order_by(community::published.desc()), SortType::New => query = query.order_by(community::published.desc()),
SortType::TopAll => query = query.order_by(community_aggregates::subscribers.desc()), SortType::TopAll => query = query.order_by(community_aggregates::subscribers.desc()),
SortType::TopMonth => query = query.order_by(community_aggregates::users_active_month.desc()), SortType::TopMonth => query = query.order_by(community_aggregates::users_active_month.desc()),
@ -198,15 +198,17 @@ impl<'a> CommunityQueryBuilder<'a> {
} }
}; };
if !self.show_nsfw { if !self.show_nsfw.unwrap_or(true) {
query = query.filter(community::nsfw.eq(false)); query = query.filter(community::nsfw.eq(false));
}; };
query = match self.listing_type { if let Some(listing_type) = self.listing_type {
query = match listing_type {
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)), ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
ListingType::Local => query.filter(community::local.eq(true)), ListingType::Local => query.filter(community::local.eq(true)),
_ => query, _ => query,
}; };
}
let (limit, offset) = limit_and_offset(self.page, self.limit); let (limit, offset) = limit_and_offset(self.page, self.limit);
let res = query let res = query

View file

@ -155,8 +155,8 @@ pub struct PersonMentionQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
my_person_id: Option<PersonId>, my_person_id: Option<PersonId>,
recipient_id: Option<PersonId>, recipient_id: Option<PersonId>,
sort: &'a SortType, sort: Option<SortType>,
unread_only: bool, unread_only: Option<bool>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
} }
@ -167,20 +167,20 @@ impl<'a> PersonMentionQueryBuilder<'a> {
conn, conn,
my_person_id: None, my_person_id: None,
recipient_id: None, recipient_id: None,
sort: &SortType::New, sort: None,
unread_only: false, unread_only: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn sort(mut self, sort: &'a SortType) -> Self { pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
self.sort = sort; self.sort = sort.get_optional();
self self
} }
pub fn unread_only(mut self, unread_only: bool) -> Self { pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
self.unread_only = unread_only; self.unread_only = unread_only.get_optional();
self self
} }
@ -264,11 +264,11 @@ impl<'a> PersonMentionQueryBuilder<'a> {
query = query.filter(person_mention::recipient_id.eq(recipient_id)); query = query.filter(person_mention::recipient_id.eq(recipient_id));
} }
if self.unread_only { if self.unread_only.unwrap_or(false) {
query = query.filter(person_mention::read.eq(false)); query = query.filter(person_mention::read.eq(false));
} }
query = match self.sort { query = match self.sort.unwrap_or(SortType::Hot) {
SortType::Hot | SortType::Active => query SortType::Hot | SortType::Active => query
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc()) .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
.then_order_by(comment_aggregates::published.desc()), .then_order_by(comment_aggregates::published.desc()),

View file

@ -57,7 +57,7 @@ impl PersonViewSafe {
pub struct PersonQueryBuilder<'a> { pub struct PersonQueryBuilder<'a> {
conn: &'a PgConnection, conn: &'a PgConnection,
sort: &'a SortType, sort: Option<SortType>,
search_term: Option<String>, search_term: Option<String>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
@ -68,14 +68,14 @@ impl<'a> PersonQueryBuilder<'a> {
PersonQueryBuilder { PersonQueryBuilder {
conn, conn,
search_term: None, search_term: None,
sort: &SortType::Hot, sort: None,
page: None, page: None,
limit: None, limit: None,
} }
} }
pub fn sort(mut self, sort: &'a SortType) -> Self { pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
self.sort = sort; self.sort = sort.get_optional();
self self
} }
@ -104,7 +104,7 @@ impl<'a> PersonQueryBuilder<'a> {
query = query.filter(person::name.ilike(fuzzy_search(&search_term))); query = query.filter(person::name.ilike(fuzzy_search(&search_term)));
} }
query = match self.sort { query = match self.sort.unwrap_or(SortType::Hot) {
SortType::Hot => query SortType::Hot => query
.order_by(person_aggregates::comment_score.desc()) .order_by(person_aggregates::comment_score.desc())
.then_order_by(person::published.desc()), .then_order_by(person::published.desc()),

View file

@ -90,11 +90,10 @@ async fn get_feed_data(
) -> Result<HttpResponse, LemmyError> { ) -> Result<HttpResponse, LemmyError> {
let site_view = blocking(context.pool(), move |conn| SiteView::read(&conn)).await??; let site_view = blocking(context.pool(), move |conn| SiteView::read(&conn)).await??;
let listing_type_ = listing_type.clone();
let posts = blocking(context.pool(), move |conn| { let posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(&conn) PostQueryBuilder::create(&conn)
.listing_type(&listing_type_) .listing_type(listing_type)
.sort(&sort_type) .sort(sort_type)
.list() .list()
}) })
.await??; .await??;
@ -174,8 +173,8 @@ fn get_feed_user(
let person = Person::find_by_name(&conn, &user_name)?; let person = Person::find_by_name(&conn, &user_name)?;
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::All) .listing_type(ListingType::All)
.sort(sort_type) .sort(*sort_type)
.creator_id(person.id) .creator_id(person.id)
.list()?; .list()?;
@ -200,8 +199,8 @@ fn get_feed_community(
let community = Community::read_from_name(&conn, &community_name)?; let community = Community::read_from_name(&conn, &community_name)?;
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::All) .listing_type(ListingType::All)
.sort(sort_type) .sort(*sort_type)
.community_id(community.id) .community_id(community.id)
.list()?; .list()?;
@ -234,11 +233,11 @@ fn get_feed_front(
let show_read_posts = local_user.show_read_posts; let show_read_posts = local_user.show_read_posts;
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::Subscribed) .listing_type(ListingType::Subscribed)
.my_person_id(person_id) .my_person_id(person_id)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.sort(sort_type) .sort(*sort_type)
.list()?; .list()?;
let items = create_post_items(posts)?; let items = create_post_items(posts)?;
@ -270,13 +269,13 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Le
.recipient_id(person_id) .recipient_id(person_id)
.my_person_id(person_id) .my_person_id(person_id)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.sort(&sort) .sort(sort)
.list()?; .list()?;
let mentions = PersonMentionQueryBuilder::create(&conn) let mentions = PersonMentionQueryBuilder::create(&conn)
.recipient_id(person_id) .recipient_id(person_id)
.my_person_id(person_id) .my_person_id(person_id)
.sort(&sort) .sort(sort)
.list()?; .list()?;
let items = create_reply_and_mention_items(replies, mentions)?; let items = create_reply_and_mention_items(replies, mentions)?;