mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-10-01 01:36:12 -04:00
Some API cleanup, adding site_id to site aggregates.
This commit is contained in:
parent
3f36730dba
commit
2d7d9cf7d8
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ use lemmy_db::{
|
||||
post::Post,
|
||||
},
|
||||
views::comment_view::CommentView,
|
||||
Crud,
|
||||
Likeable,
|
||||
};
|
||||
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
|
||||
|
@ -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,
|
||||
|
@ -27,6 +27,7 @@ use lemmy_db::{
|
||||
user_view::UserViewSafe,
|
||||
},
|
||||
ApubObject,
|
||||
Crud,
|
||||
Joinable,
|
||||
SearchType,
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user