Some API cleanup, adding site_id to site aggregates.

This commit is contained in:
Dessalines 2020-12-19 20:10:47 -05:00
parent 3f36730dba
commit 2d7d9cf7d8
25 changed files with 247 additions and 236 deletions

View file

@ -1,5 +1,6 @@
use crate::{
check_community_ban,
check_downvotes_enabled,
collect_moderated_communities,
get_post,
get_user_from_jwt,
@ -11,16 +12,13 @@ use actix_web::web::Data;
use lemmy_apub::{ApubLikeableType, ApubObjectType};
use lemmy_db::{
source::{
comment::*,
comment::{Comment, CommentForm, CommentLike, CommentLikeForm, CommentSaved, CommentSavedForm},
comment_report::{CommentReport, CommentReportForm},
moderator::*,
post::*,
user::*,
moderator::{ModRemoveComment, ModRemoveCommentForm},
},
views::{
comment_report_view::{CommentReportQueryBuilder, CommentReportView},
comment_view::{CommentQueryBuilder, CommentView},
site_view::SiteView,
},
Crud,
Likeable,
@ -110,6 +108,7 @@ impl Perform for CreateComment {
updated_comment.send_create(&user, context).await?;
// Scan the comment for user mentions, add those rows
let post_id = post.id;
let mentions = scrape_text_for_mentions(&comment_form.content);
let recipient_ids = send_local_notifs(
mentions,
@ -124,7 +123,7 @@ impl Perform for CreateComment {
// You like your own comment by default
let like_form = CommentLikeForm {
comment_id: inserted_comment.id,
post_id: data.post_id,
post_id,
user_id: user.id,
score: 1,
};
@ -156,6 +155,7 @@ impl Perform for CreateComment {
// strip out the recipient_ids, so that
// users don't get double notifs
// TODO Do this in a different way
res.recipient_ids = Vec::new();
Ok(res)
@ -203,16 +203,13 @@ impl Perform for EditComment {
updated_comment.send_update(&user, context).await?;
// Do the mentions / recipients
let post_id = orig_comment.post.id;
let post = get_post(post_id, context.pool()).await?;
let updated_comment_content = updated_comment.content.to_owned();
let mentions = scrape_text_for_mentions(&updated_comment_content);
let recipient_ids = send_local_notifs(
mentions,
updated_comment,
&user,
post,
orig_comment.post,
context.pool(),
false,
)
@ -239,6 +236,7 @@ impl Perform for EditComment {
// strip out the recipient_ids, so that
// users don't get double notifs
// TODO again
res.recipient_ids = Vec::new();
Ok(res)
@ -297,14 +295,13 @@ impl Perform for DeleteComment {
.await??;
// Build the recipients
let post_id = comment_view.post.id;
let post = get_post(post_id, context.pool()).await?;
let comment_view_2 = comment_view.clone();
let mentions = vec![];
let recipient_ids = send_local_notifs(
mentions,
updated_comment,
&user,
post,
comment_view_2.post,
context.pool(),
false,
)
@ -313,7 +310,7 @@ impl Perform for DeleteComment {
let mut res = CommentResponse {
comment_view,
recipient_ids,
form_id: None,
form_id: None, // TODO a comment delete might clear forms?
};
context.chat_server().do_send(SendComment {
@ -324,6 +321,7 @@ impl Perform for DeleteComment {
// strip out the recipient_ids, so that
// users don't get double notifs
// TODO again
res.recipient_ids = Vec::new();
Ok(res)
@ -392,14 +390,14 @@ impl Perform for RemoveComment {
.await??;
// Build the recipients
let post_id = comment_view.post.id;
let post = get_post(post_id, context.pool()).await?;
let comment_view_2 = comment_view.clone();
let mentions = vec![];
let recipient_ids = send_local_notifs(
mentions,
updated_comment,
&user,
post,
comment_view_2.post,
context.pool(),
false,
)
@ -408,7 +406,7 @@ impl Perform for RemoveComment {
let mut res = CommentResponse {
comment_view,
recipient_ids,
form_id: None,
form_id: None, // TODO maybe this might clear other forms
};
context.chat_server().do_send(SendComment {
@ -419,6 +417,7 @@ impl Perform for RemoveComment {
// strip out the recipient_ids, so that
// users don't get double notifs
// TODO again
res.recipient_ids = Vec::new();
Ok(res)
@ -437,41 +436,23 @@ impl Perform for MarkCommentAsRead {
let data: &MarkCommentAsRead = &self;
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
let edit_id = data.edit_id;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
CommentView::read(&conn, edit_id, None)
CommentView::read(&conn, comment_id, None)
})
.await??;
check_community_ban(user.id, orig_comment.community.id, context.pool()).await?;
// Verify that only the recipient can mark as read
// Needs to fetch the parent comment / post to get the recipient
let parent_id = orig_comment.comment.parent_id;
match parent_id {
Some(pid) => {
let parent_comment = blocking(context.pool(), move |conn| {
CommentView::read(&conn, pid, None)
})
.await??;
if user.id != parent_comment.creator.id {
return Err(APIError::err("no_comment_edit_allowed").into());
}
}
None => {
let parent_post_id = orig_comment.post.id;
let parent_post =
blocking(context.pool(), move |conn| Post::read(conn, parent_post_id)).await??;
if user.id != parent_post.creator_id {
return Err(APIError::err("no_comment_edit_allowed").into());
}
}
if user.id != orig_comment.get_recipient_id() {
return Err(APIError::err("no_comment_edit_allowed").into());
}
// Do the mark as read
let read = data.read;
match blocking(context.pool(), move |conn| {
Comment::update_read(conn, edit_id, read)
Comment::update_read(conn, comment_id, read)
})
.await?
{
@ -480,7 +461,7 @@ impl Perform for MarkCommentAsRead {
};
// Refetch it
let edit_id = data.edit_id;
let edit_id = data.comment_id;
let user_id = user.id;
let comment_view = blocking(context.pool(), move |conn| {
CommentView::read(conn, edit_id, Some(user_id))
@ -556,12 +537,7 @@ impl Perform for CreateCommentLike {
let mut recipient_ids = Vec::new();
// Don't do a downvote if site has downvotes disabled
if data.score == -1 {
let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
if !site_view.site.enable_downvotes {
return Err(APIError::err("downvotes_disabled").into());
}
}
check_downvotes_enabled(data.score, context.pool()).await?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
@ -569,34 +545,14 @@ impl Perform for CreateCommentLike {
})
.await??;
let post_id = orig_comment.post.id;
let post = get_post(post_id, context.pool()).await?;
check_community_ban(user.id, post.community_id, context.pool()).await?;
check_community_ban(user.id, orig_comment.community.id, context.pool()).await?;
let comment_id = data.comment_id;
let comment = blocking(context.pool(), move |conn| Comment::read(conn, comment_id)).await??;
// Add to recipient ids
match comment.parent_id {
Some(parent_id) => {
let parent_comment =
blocking(context.pool(), move |conn| Comment::read(conn, parent_id)).await??;
if parent_comment.creator_id != user.id {
let parent_user = blocking(context.pool(), move |conn| {
User_::read(conn, parent_comment.creator_id)
})
.await??;
recipient_ids.push(parent_user.id);
}
}
None => {
recipient_ids.push(post.creator_id);
}
}
// Add parent user to recipients
recipient_ids.push(orig_comment.get_recipient_id());
let like_form = CommentLikeForm {
comment_id: data.comment_id,
post_id,
post_id: orig_comment.post.id,
user_id: user.id,
score: data.score,
};
@ -609,6 +565,7 @@ impl Perform for CreateCommentLike {
.await??;
// Only add the like if the score isnt 0
let comment = orig_comment.comment;
let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
if do_add {
let like_form2 = like_form.clone();
@ -649,6 +606,7 @@ impl Perform for CreateCommentLike {
// strip out the recipient_ids, so that
// users don't get double notifs
res.recipient_ids = Vec::new();
// TODO why
Ok(res)
}

View file

@ -58,20 +58,22 @@ impl Perform for GetCommunity {
let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?;
let user_id = user.map(|u| u.id);
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
let community = match data.id {
Some(id) => blocking(context.pool(), move |conn| Community::read(conn, id)).await??,
None => match blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &name)
})
.await?
{
Ok(community) => community,
Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
},
let community_id = match data.id {
Some(id) => id,
None => {
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
match blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &name)
})
.await?
{
Ok(community) => community,
Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
}
.id
}
};
let community_id = community.id;
let community_view = match blocking(context.pool(), move |conn| {
CommunityView::read(conn, community_id, user_id)
})
@ -81,7 +83,6 @@ impl Perform for GetCommunity {
Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
};
let community_id = community.id;
let moderators: Vec<CommunityModeratorView> = match blocking(context.pool(), move |conn| {
CommunityModeratorView::for_community(conn, community_id)
})
@ -178,6 +179,7 @@ impl Perform for CreateCommunity {
Err(_e) => return Err(APIError::err("community_already_exists").into()),
};
// The community creator becomes a moderator
let community_moderator_form = CommunityModeratorForm {
community_id: inserted_community.id,
user_id: user.id,
@ -188,6 +190,7 @@ impl Perform for CreateCommunity {
return Err(APIError::err("community_moderator_already_exists").into());
}
// Follow your own community
let community_follower_form = CommunityFollowerForm {
community_id: inserted_community.id,
user_id: user.id,
@ -584,15 +587,15 @@ impl Perform for BanFromCommunity {
}
// Remove/Restore their data if that's desired
if let Some(remove_data) = data.remove_data {
if data.remove_data {
// Posts
blocking(context.pool(), move |conn: &'_ _| {
Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), remove_data)
Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), true)
})
.await??;
// Comments
// Diesel doesn't allow updates with joins, so this has to be a loop
// TODO Diesel doesn't allow updates with joins, so this has to be a loop
let comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn)
.creator_id(banned_user_id)
@ -605,7 +608,7 @@ impl Perform for BanFromCommunity {
for comment_view in &comments {
let comment_id = comment_view.comment.id;
blocking(context.pool(), move |conn: &'_ _| {
Comment::update_removed(conn, comment_id, remove_data)
Comment::update_removed(conn, comment_id, true)
})
.await??;
}
@ -743,6 +746,7 @@ impl Perform for TransferCommunity {
let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
// Making sure the creator, if an admin, is at the top
let creator_index = admins
.iter()
.position(|r| r.user.id == site_creator_id)

View file

@ -4,6 +4,7 @@ use lemmy_db::{
source::{
community::{Community, CommunityModerator},
post::Post,
site::Site,
user::User_,
},
views::community::community_user_ban_view::CommunityUserBanView,
@ -102,6 +103,16 @@ pub(crate) async fn check_community_ban(
}
}
pub(crate) async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
if score == -1 {
let site = blocking(pool, move |conn| Site::read_simple(conn)).await??;
if !site.enable_downvotes {
return Err(APIError::err("downvotes_disabled").into());
}
}
Ok(())
}
/// Returns a list of communities that the user moderates
/// or if a community_id is supplied validates the user is a moderator
/// of that community and returns the community id in a vec

View file

@ -1,5 +1,6 @@
use crate::{
check_community_ban,
check_downvotes_enabled,
check_optional_url,
collect_moderated_communities,
get_user_from_jwt,
@ -18,10 +19,9 @@ use lemmy_db::{
},
views::{
comment_view::CommentQueryBuilder,
community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView},
community::community_moderator_view::CommunityModeratorView,
post_report_view::{PostReportQueryBuilder, PostReportView},
post_view::{PostQueryBuilder, PostView},
site_view::SiteView,
},
Crud,
Likeable,
@ -192,12 +192,6 @@ impl Perform for GetPost {
})
.await??;
let community_id = post_view.community.id;
let community = blocking(context.pool(), move |conn| {
CommunityView::read(conn, community_id, user_id)
})
.await??;
let community_id = post_view.community.id;
let moderators = blocking(context.pool(), move |conn| {
CommunityModeratorView::for_community(conn, community_id)
@ -214,7 +208,6 @@ impl Perform for GetPost {
Ok(GetPostResponse {
post_view,
comments,
community,
moderators,
online,
})
@ -285,12 +278,7 @@ impl Perform for CreatePostLike {
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
// Don't do a downvote if site has downvotes disabled
if data.score == -1 {
let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
if !site_view.site.enable_downvotes {
return Err(APIError::err("downvotes_disabled").into());
}
}
check_downvotes_enabled(data.score, context.pool()).await?;
// Check for a community ban
let post_id = data.post_id;

View file

@ -10,7 +10,6 @@ use actix_web::web::Data;
use anyhow::Context;
use lemmy_apub::fetcher::search_by_apub_id;
use lemmy_db::{
aggregates::site_aggregates::SiteAggregates,
diesel_option_overwrite,
naive_now,
source::{category::*, moderator::*, site::*},
@ -156,7 +155,7 @@ impl Perform for CreateSite {
) -> Result<SiteResponse, LemmyError> {
let data: &CreateSite = &self;
let read_site = move |conn: &'_ _| Site::read(conn, 1);
let read_site = move |conn: &'_ _| Site::read_simple(conn);
if blocking(context.pool(), read_site).await?.is_ok() {
return Err(APIError::err("site_already_exists").into());
};
@ -188,7 +187,7 @@ impl Perform for CreateSite {
let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
Ok(SiteResponse { site: site_view })
Ok(SiteResponse { site_view })
}
}
@ -209,7 +208,7 @@ impl Perform for EditSite {
// Make sure user is an admin
is_admin(context.pool(), user.id).await?;
let found_site = blocking(context.pool(), move |conn| Site::read(conn, 1)).await??;
let found_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??;
let icon = diesel_option_overwrite(&data.icon);
let banner = diesel_option_overwrite(&data.banner);
@ -233,7 +232,7 @@ impl Perform for EditSite {
let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
let res = SiteResponse { site: site_view };
let res = SiteResponse { site_view };
context.chat_server().do_send(SendAllMessage {
op: UserOperation::EditSite,
@ -256,39 +255,41 @@ impl Perform for GetSite {
) -> Result<GetSiteResponse, LemmyError> {
let data: &GetSite = &self;
// TODO refactor this a little
let res = blocking(context.pool(), move |conn| Site::read(conn, 1)).await?;
let site_view = if res.is_ok() {
Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
} else if let Some(setup) = Settings::get().setup.as_ref() {
let register = Register {
username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(),
password: setup.admin_password.to_owned(),
password_verify: setup.admin_password.to_owned(),
admin: true,
show_nsfw: true,
captcha_uuid: None,
captcha_answer: None,
};
let login_response = register.perform(context, websocket_id).await?;
info!("Admin {} created", setup.admin_username);
let site_view = match blocking(context.pool(), move |conn| SiteView::read(conn)).await? {
Ok(site_view) => Some(site_view),
// If the site isn't created yet, check the setup
Err(_) => {
if let Some(setup) = Settings::get().setup.as_ref() {
let register = Register {
username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(),
password: setup.admin_password.to_owned(),
password_verify: setup.admin_password.to_owned(),
admin: true,
show_nsfw: true,
captcha_uuid: None,
captcha_answer: None,
};
let login_response = register.perform(context, websocket_id).await?;
info!("Admin {} created", setup.admin_username);
let create_site = CreateSite {
name: setup.site_name.to_owned(),
description: None,
icon: None,
banner: None,
enable_downvotes: true,
open_registration: true,
enable_nsfw: true,
auth: login_response.jwt,
};
create_site.perform(context, websocket_id).await?;
info!("Site {} created", setup.site_name);
Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
} else {
None
let create_site = CreateSite {
name: setup.site_name.to_owned(),
description: None,
icon: None,
banner: None,
enable_downvotes: true,
open_registration: true,
enable_nsfw: true,
auth: login_response.jwt,
};
create_site.perform(context, websocket_id).await?;
info!("Site {} created", setup.site_name);
Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
} else {
None
}
}
};
let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
@ -321,17 +322,14 @@ impl Perform for GetSite {
u
});
let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
Ok(GetSiteResponse {
site: site_view,
site_view,
admins,
banned,
online,
version: version::VERSION.to_string(),
my_user,
federated_instances: linked_instances(context.pool()).await?,
counts,
})
}
}
@ -521,7 +519,7 @@ impl Perform for TransferSite {
user.private_key = None;
user.public_key = None;
let read_site = blocking(context.pool(), move |conn| Site::read(conn, 1)).await??;
let read_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??;
// Make sure user is the creator
if read_site.creator_id != user.id {
@ -555,17 +553,14 @@ impl Perform for TransferSite {
let banned = blocking(context.pool(), move |conn| UserViewSafe::banned(conn)).await??;
let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
Ok(GetSiteResponse {
site: Some(site_view),
site_view: Some(site_view),
admins,
banned,
online: 0,
version: version::VERSION.to_string(),
my_user: Some(user),
federated_instances: linked_instances(context.pool()).await?,
counts,
})
}
}
@ -604,12 +599,8 @@ impl Perform for SaveSiteConfig {
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
// Only let admins read this
let admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
let admin_ids: Vec<i32> = admins.into_iter().map(|m| m.user.id).collect();
if !admin_ids.contains(&user.id) {
return Err(APIError::err("not_an_admin").into());
}
let user_id = user.id;
is_admin(context.pool(), user_id).await?;
// Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem
let config_hjson = match Settings::save_config_file(&data.config_hjson) {

View file

@ -38,7 +38,6 @@ use lemmy_db::{
post_report_view::PostReportView,
post_view::PostQueryBuilder,
private_message_view::{PrivateMessageQueryBuilder, PrivateMessageView},
site_view::SiteView,
user_mention_view::{UserMentionQueryBuilder, UserMentionView},
user_view::{UserViewDangerous, UserViewSafe},
},
@ -120,8 +119,8 @@ impl Perform for Register {
let data: &Register = &self;
// Make sure site has open registration
if let Ok(site_view) = blocking(context.pool(), move |conn| SiteView::read(conn)).await? {
if !site_view.site.open_registration {
if let Ok(site) = blocking(context.pool(), move |conn| Site::read_simple(conn)).await? {
if !site.open_registration {
return Err(APIError::err("registration_closed").into());
}
}
@ -347,9 +346,6 @@ impl Perform for SaveUserSettings {
let data: &SaveUserSettings = &self;
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
let user_id = user.id;
let read_user = blocking(context.pool(), move |conn| User_::read(conn, user_id)).await??;
let avatar = diesel_option_overwrite(&data.avatar);
let banner = diesel_option_overwrite(&data.banner);
let email = diesel_option_overwrite(&data.email);
@ -373,6 +369,7 @@ impl Perform for SaveUserSettings {
}
}
let user_id = user.id;
let password_encrypted = match &data.new_password {
Some(new_password) => {
match &data.new_password_verify {
@ -385,8 +382,7 @@ impl Perform for SaveUserSettings {
// Check the old password
match &data.old_password {
Some(old_password) => {
let valid: bool =
verify(old_password, &read_user.password_encrypted).unwrap_or(false);
let valid: bool = verify(old_password, &user.password_encrypted).unwrap_or(false);
if !valid {
return Err(APIError::err("password_incorrect").into());
}
@ -403,33 +399,36 @@ impl Perform for SaveUserSettings {
None => return Err(APIError::err("passwords_dont_match").into()),
}
}
None => read_user.password_encrypted,
None => user.password_encrypted,
};
let default_listing_type = ListingType::from_str(&data.default_listing_type)? as i16;
let default_sort_type = SortType::from_str(&data.default_sort_type)? as i16;
let user_form = UserForm {
name: read_user.name,
name: user.name,
email,
matrix_user_id,
avatar,
banner,
password_encrypted,
preferred_username,
published: Some(read_user.published),
published: Some(user.published),
updated: Some(naive_now()),
admin: read_user.admin,
banned: Some(read_user.banned),
admin: user.admin,
banned: Some(user.banned),
show_nsfw: data.show_nsfw,
theme: data.theme.to_owned(),
default_sort_type: data.default_sort_type,
default_listing_type: data.default_listing_type,
default_sort_type,
default_listing_type,
lang: data.lang.to_owned(),
show_avatars: data.show_avatars,
send_notifications_to_email: data.send_notifications_to_email,
actor_id: Some(read_user.actor_id),
actor_id: Some(user.actor_id),
bio,
local: read_user.local,
private_key: read_user.private_key,
public_key: read_user.public_key,
local: user.local,
private_key: user.private_key,
public_key: user.public_key,
last_refreshed_at: None,
};
@ -579,9 +578,8 @@ impl Perform for GetUserDetails {
// Return the jwt
Ok(GetUserDetailsResponse {
// TODO need to figure out dangerous user view here
user: user_view,
user_dangerous,
user_view,
user_view_dangerous: user_dangerous,
follows,
moderates,
comments,
@ -669,22 +667,22 @@ impl Perform for BanUser {
}
// Remove their data if that's desired
if let Some(remove_data) = data.remove_data {
if data.remove_data {
// Posts
blocking(context.pool(), move |conn: &'_ _| {
Post::update_removed_for_creator(conn, banned_user_id, None, remove_data)
Post::update_removed_for_creator(conn, banned_user_id, None, true)
})
.await??;
// Communities
blocking(context.pool(), move |conn: &'_ _| {
Community::update_removed_for_creator(conn, banned_user_id, remove_data)
Community::update_removed_for_creator(conn, banned_user_id, true)
})
.await??;
// Comments
blocking(context.pool(), move |conn: &'_ _| {
Comment::update_removed_for_creator(conn, banned_user_id, remove_data)
Comment::update_removed_for_creator(conn, banned_user_id, true)
})
.await??;
}
@ -712,7 +710,7 @@ impl Perform for BanUser {
.await??;
let res = BanUserResponse {
user: user_view,
user_view,
banned: data.ban,
};
@ -1091,7 +1089,9 @@ impl Perform for CreatePrivateMessage {
})
.await??;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::CreatePrivateMessage,
@ -1148,7 +1148,9 @@ impl Perform for EditPrivateMessage {
.await??;
let recipient_id = message.recipient.id;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::EditPrivateMessage,
@ -1211,7 +1213,9 @@ impl Perform for DeletePrivateMessage {
.await??;
let recipient_id = message.recipient.id;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::DeletePrivateMessage,
@ -1267,7 +1271,9 @@ impl Perform for MarkPrivateMessageAsRead {
.await??;
let recipient_id = message.recipient.id;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::MarkPrivateMessageAsRead,
@ -1305,7 +1311,9 @@ impl Perform for GetPrivateMessages {
})
.await??;
Ok(PrivateMessagesResponse { messages })
Ok(PrivateMessagesResponse {
private_messages: messages,
})
}
}

View file

@ -10,6 +10,7 @@ use lemmy_db::{
post::Post,
},
views::comment_view::CommentView,
Crud,
Likeable,
};
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};

View file

@ -47,9 +47,11 @@ pub(crate) async fn receive_create_private_message(
})
.await??;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
let recipient_id = res.message.recipient.id;
let recipient_id = res.private_message_view.recipient.id;
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::CreatePrivateMessage,
@ -85,9 +87,11 @@ pub(crate) async fn receive_update_private_message(
})
.await??;
let res = PrivateMessageResponse { message };
let res = PrivateMessageResponse {
private_message_view: message,
};
let recipient_id = res.message.recipient.id;
let recipient_id = res.private_message_view.recipient.id;
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::EditPrivateMessage,
@ -117,8 +121,10 @@ pub(crate) async fn receive_delete_private_message(
})
.await??;
let res = PrivateMessageResponse { message };
let recipient_id = res.message.recipient.id;
let res = PrivateMessageResponse {
private_message_view: message,
};
let recipient_id = res.private_message_view.recipient.id;
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::EditPrivateMessage,
response: res,
@ -152,8 +158,10 @@ pub(crate) async fn receive_undo_delete_private_message(
})
.await??;
let res = PrivateMessageResponse { message };
let recipient_id = res.message.recipient.id;
let res = PrivateMessageResponse {
private_message_view: message,
};
let recipient_id = res.private_message_view.recipient.id;
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::EditPrivateMessage,
response: res,

View file

@ -27,6 +27,7 @@ use lemmy_db::{
user_view::UserViewSafe,
},
ApubObject,
Crud,
Joinable,
SearchType,
};

View file

@ -4,7 +4,7 @@ use crate::{
};
use actix_web::{body::Body, web, HttpResponse};
use diesel::result::Error::NotFound;
use lemmy_db::source::post::Post;
use lemmy_db::{source::post::Post, Crud};
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;

View file

@ -2,10 +2,11 @@ use crate::schema::site_aggregates;
use diesel::{result::Error, *};
use serde::Serialize;
#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Clone)]
#[table_name = "site_aggregates"]
pub struct SiteAggregates {
pub id: i32,
pub site_id: i32,
pub users: i64,
pub posts: i64,
pub comments: i64,

View file

@ -362,6 +362,7 @@ table! {
table! {
site_aggregates (id) {
id -> Int4,
site_id -> Int4,
users -> Int8,
posts -> Int8,
comments -> Int8,
@ -560,6 +561,7 @@ joinable!(post_report -> post (post_id));
joinable!(post_saved -> post (post_id));
joinable!(post_saved -> user_ (user_id));
joinable!(site -> user_ (creator_id));
joinable!(site_aggregates -> site (site_id));
joinable!(user_aggregates -> user_ (user_id));
joinable!(user_ban -> user_ (user_id));
joinable!(user_mention -> comment (comment_id));

View file

@ -106,11 +106,6 @@ impl ApubObject<PostForm> for Post {
}
impl Post {
pub fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
post.filter(id.eq(post_id)).first::<Self>(conn)
}
pub fn list_for_community(
conn: &PgConnection,
the_community_id: i32,

View file

@ -59,4 +59,9 @@ impl Site {
.set((creator_id.eq(new_creator_id), updated.eq(naive_now())))
.get_result::<Self>(conn)
}
pub fn read_simple(conn: &PgConnection) -> Result<Self, Error> {
use crate::schema::site::dsl::*;
site.first::<Self>(conn)
}
}

View file

@ -145,6 +145,15 @@ impl CommentView {
my_vote,
})
}
/// Gets the recipient user id.
/// If there is no parent comment, its the post creator
pub fn get_recipient_id(&self) -> i32 {
match &self.recipient {
Some(parent_commenter) => parent_commenter.id,
None => self.post.creator_id,
}
}
}
pub struct CommentQueryBuilder<'a> {

View file

@ -1,5 +1,6 @@
use crate::{
schema::{site, user_},
aggregates::site_aggregates::SiteAggregates,
schema::{site, site_aggregates, user_},
source::{
site::Site,
user::{UserSafe, User_},
@ -13,15 +14,25 @@ use serde::Serialize;
pub struct SiteView {
pub site: Site,
pub creator: UserSafe,
pub counts: SiteAggregates,
}
impl SiteView {
pub fn read(conn: &PgConnection) -> Result<Self, Error> {
let (site, creator) = site::table
let (site, creator, counts) = site::table
.inner_join(user_::table)
.select((site::all_columns, User_::safe_columns_tuple()))
.first::<(Site, UserSafe)>(conn)?;
.inner_join(site_aggregates::table)
.select((
site::all_columns,
User_::safe_columns_tuple(),
site_aggregates::all_columns,
))
.first::<(Site, UserSafe, SiteAggregates)>(conn)?;
Ok(SiteView { site, creator })
Ok(SiteView {
site,
creator,
counts,
})
}
}

View file

@ -35,7 +35,7 @@ pub struct RemoveComment {
#[derive(Deserialize)]
pub struct MarkCommentAsRead {
pub edit_id: i32,
pub comment_id: i32,
pub read: bool,
pub auth: String,
}
@ -50,8 +50,8 @@ pub struct SaveComment {
#[derive(Serialize, Clone)]
pub struct CommentResponse {
pub comment_view: CommentView,
pub recipient_ids: Vec<i32>,
pub form_id: Option<String>,
pub recipient_ids: Vec<i32>, // TODO another way to do this? Maybe a UserMention belongs to Comment
pub form_id: Option<String>, // An optional front end ID, to tell which is coming back
}
#[derive(Deserialize)]
@ -98,6 +98,7 @@ pub struct ResolveCommentReport {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ResolveCommentReportResponse {
// TODO this should probably return the view
pub report_id: i32,
pub resolved: bool,
}

View file

@ -57,7 +57,7 @@ pub struct BanFromCommunity {
pub community_id: i32,
pub user_id: i32,
pub ban: bool,
pub remove_data: Option<bool>,
pub remove_data: bool,
pub reason: Option<String>,
pub expires: Option<i64>,
pub auth: String,

View file

@ -3,7 +3,6 @@ pub mod community;
pub mod post;
pub mod site;
pub mod user;
pub mod websocket;
use diesel::PgConnection;
use lemmy_db::{

View file

@ -1,6 +1,6 @@
use lemmy_db::views::{
comment_view::CommentView,
community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView},
community::community_moderator_view::CommunityModeratorView,
post_report_view::PostReportView,
post_view::PostView,
};
@ -31,7 +31,6 @@ pub struct GetPost {
pub struct GetPostResponse {
pub post_view: PostView,
pub comments: Vec<CommentView>,
pub community: CommunityView,
pub moderators: Vec<CommunityModeratorView>,
pub online: usize,
}

View file

@ -1,5 +1,4 @@
use lemmy_db::{
aggregates::site_aggregates::SiteAggregates,
source::{category::*, user::*},
views::{
comment_view::CommentView,
@ -101,16 +100,14 @@ pub struct GetSite {
pub auth: Option<String>,
}
// TODO combine siteresponse and getsiteresponse
#[derive(Serialize, Clone)]
pub struct SiteResponse {
pub site: SiteView,
pub site_view: SiteView,
}
#[derive(Serialize)]
pub struct GetSiteResponse {
pub site: Option<SiteView>, // Because the site might not be set up yet
pub counts: SiteAggregates,
pub site_view: Option<SiteView>, // Because the site might not be set up yet
pub admins: Vec<UserViewSafe>,
pub banned: Vec<UserViewSafe>,
pub online: usize,

View file

@ -48,8 +48,8 @@ pub struct CaptchaResponse {
pub struct SaveUserSettings {
pub show_nsfw: bool,
pub theme: String,
pub default_sort_type: i16,
pub default_listing_type: i16,
pub default_sort_type: String,
pub default_listing_type: String,
pub lang: String,
pub avatar: Option<String>,
pub banner: Option<String>,
@ -84,8 +84,8 @@ pub struct GetUserDetails {
#[derive(Serialize)]
pub struct GetUserDetailsResponse {
pub user: Option<UserViewSafe>,
pub user_dangerous: Option<UserViewDangerous>,
pub user_view: Option<UserViewSafe>,
pub user_view_dangerous: Option<UserViewDangerous>,
pub follows: Vec<CommunityFollowerView>,
pub moderates: Vec<CommunityModeratorView>,
pub comments: Vec<CommentView>,
@ -123,7 +123,7 @@ pub struct AddAdminResponse {
pub struct BanUser {
pub user_id: i32,
pub ban: bool,
pub remove_data: Option<bool>,
pub remove_data: bool,
pub reason: Option<String>,
pub expires: Option<i64>,
pub auth: String,
@ -131,7 +131,7 @@ pub struct BanUser {
#[derive(Serialize, Clone)]
pub struct BanUserResponse {
pub user: UserViewSafe,
pub user_view: UserViewSafe,
pub banned: bool,
}
@ -224,12 +224,12 @@ pub struct GetPrivateMessages {
#[derive(Serialize, Clone)]
pub struct PrivateMessagesResponse {
pub messages: Vec<PrivateMessageView>,
pub private_messages: Vec<PrivateMessageView>,
}
#[derive(Serialize, Clone)]
pub struct PrivateMessageResponse {
pub message: PrivateMessageView,
pub private_message_view: PrivateMessageView,
}
#[derive(Deserialize, Debug)]

View file

@ -1 +0,0 @@

View file

@ -1,10 +1,12 @@
-- Site aggregates
drop table site_aggregates;
drop trigger site_aggregates_site on site;
drop trigger site_aggregates_user on user_;
drop trigger site_aggregates_post on post;
drop trigger site_aggregates_comment on comment;
drop trigger site_aggregates_community on community;
drop function
site_aggregates_site,
site_aggregates_user,
site_aggregates_post,
site_aggregates_comment,

View file

@ -1,17 +1,38 @@
-- Add site aggregates
create table site_aggregates (
id serial primary key,
users bigint not null,
posts bigint not null,
comments bigint not null,
communities bigint not null
site_id int references site on update cascade on delete cascade not null,
users bigint not null default 0,
posts bigint not null default 0,
comments bigint not null default 0,
communities bigint not null default 0
);
insert into site_aggregates (users, posts, comments, communities)
select ( select coalesce(count(*), 0) from user_) as users,
insert into site_aggregates (site_id, users, posts, comments, communities)
select id as site_id,
( select coalesce(count(*), 0) from user_) as users,
( select coalesce(count(*), 0) from post) as posts,
( select coalesce(count(*), 0) from comment) as comments,
( select coalesce(count(*), 0) from community) as communities;
( select coalesce(count(*), 0) from community) as communities
from site;
-- initial site add
create function site_aggregates_site()
returns trigger language plpgsql
as $$
begin
IF (TG_OP = 'INSERT') THEN
insert into site_aggregates (site_id) values (NEW.id);
ELSIF (TG_OP = 'DELETE') THEN
delete from site_aggregates where site_id = OLD.id;
END IF;
return null;
end $$;
create trigger site_aggregates_site
after insert or delete on site
for each row
execute procedure site_aggregates_site();
-- Add site aggregate triggers
-- user