use crate::{
check_community_ban,
+ check_downvotes_enabled,
collect_moderated_communities,
get_post,
get_user_from_jwt,
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,
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,
// 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,
};
// 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)
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,
)
// strip out the recipient_ids, so that
// users don't get double notifs
+ // TODO again
res.recipient_ids = Vec::new();
Ok(res)
.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,
)
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 {
// strip out the recipient_ids, so that
// users don't get double notifs
+ // TODO again
res.recipient_ids = Vec::new();
Ok(res)
.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,
)
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 {
// strip out the recipient_ids, so that
// users don't get double notifs
+ // TODO again
res.recipient_ids = Vec::new();
Ok(res)
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?
{
};
// 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))
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| {
})
.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,
};
.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();
// strip out the recipient_ids, so that
// users don't get double notifs
res.recipient_ids = Vec::new();
+ // TODO why
Ok(res)
}
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)
})
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)
})
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,
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,
}
// 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)
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??;
}
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)
source::{
community::{Community, CommunityModerator},
post::Post,
+ site::Site,
user::User_,
},
views::community::community_user_ban_view::CommunityUserBanView,
}
}
+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
use crate::{
check_community_ban,
+ check_downvotes_enabled,
check_optional_url,
collect_moderated_communities,
get_user_from_jwt,
},
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,
})
.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)
Ok(GetPostResponse {
post_view,
comments,
- community,
moderators,
online,
})
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;
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::*},
) -> 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());
};
let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
- Ok(SiteResponse { site: site_view })
+ Ok(SiteResponse { site_view })
}
}
// 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);
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,
) -> 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 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 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 mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
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,
})
}
}
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 {
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,
})
}
}
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) {
post_report_view::PostReportView,
post_view::PostQueryBuilder,
private_message_view::{PrivateMessageQueryBuilder, PrivateMessageView},
- site_view::SiteView,
user_mention_view::{UserMentionQueryBuilder, UserMentionView},
user_view::{UserViewDangerous, UserViewSafe},
},
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());
}
}
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);
}
}
+ let user_id = user.id;
let password_encrypted = match &data.new_password {
Some(new_password) => {
match &data.new_password_verify {
// 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());
}
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,
};
// 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,
}
// 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??;
}
.await??;
let res = BanUserResponse {
- user: user_view,
+ user_view,
banned: data.ban,
};
})
.await??;
- let res = PrivateMessageResponse { message };
+ let res = PrivateMessageResponse {
+ private_message_view: message,
+ };
context.chat_server().do_send(SendUserRoomMessage {
op: UserOperation::CreatePrivateMessage,
.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,
.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,
.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,
})
.await??;
- Ok(PrivateMessagesResponse { messages })
+ Ok(PrivateMessagesResponse {
+ private_messages: messages,
+ })
}
}
post::Post,
},
views::comment_view::CommentView,
+ Crud,
Likeable,
};
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
})
.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,
})
.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,
})
.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,
})
.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,
user_view::UserViewSafe,
},
ApubObject,
+ Crud,
Joinable,
SearchType,
};
};
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;
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,
table! {
site_aggregates (id) {
id -> Int4,
+ site_id -> Int4,
users -> Int8,
posts -> Int8,
comments -> Int8,
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));
}
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,
.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)
+ }
}
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> {
use crate::{
- schema::{site, user_},
+ aggregates::site_aggregates::SiteAggregates,
+ schema::{site, site_aggregates, user_},
source::{
site::Site,
user::{UserSafe, User_},
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,
+ })
}
}
#[derive(Deserialize)]
pub struct MarkCommentAsRead {
- pub edit_id: i32,
+ pub comment_id: i32,
pub read: bool,
pub auth: String,
}
#[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)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ResolveCommentReportResponse {
+ // TODO this should probably return the view
pub report_id: i32,
pub resolved: bool,
}
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,
pub mod post;
pub mod site;
pub mod user;
-pub mod websocket;
use diesel::PgConnection;
use lemmy_db::{
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,
};
pub struct GetPostResponse {
pub post_view: PostView,
pub comments: Vec<CommentView>,
- pub community: CommunityView,
pub moderators: Vec<CommunityModeratorView>,
pub online: usize,
}
use lemmy_db::{
- aggregates::site_aggregates::SiteAggregates,
source::{category::*, user::*},
views::{
comment_view::CommentView,
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,
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>,
#[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>,
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,
#[derive(Serialize, Clone)]
pub struct BanUserResponse {
- pub user: UserViewSafe,
+ pub user_view: UserViewSafe,
pub banned: bool,
}
#[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)]
-- 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,
-- 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