mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-12 05:54:51 +00:00
Adding views and replaceable schema.
This commit is contained in:
parent
724856d684
commit
1053df1a4b
|
@ -7,7 +7,11 @@ use lemmy_db_schema::{
|
|||
PostListingMode,
|
||||
PostSortType,
|
||||
};
|
||||
use lemmy_db_views::structs::{CommentView, LocalImageView, PostView};
|
||||
use lemmy_db_views::structs::{
|
||||
LocalImageView,
|
||||
ProfileCombinedPaginationCursor,
|
||||
ProfileCombinedView,
|
||||
};
|
||||
use lemmy_db_views_actor::structs::{
|
||||
CommentReplyView,
|
||||
CommunityModeratorView,
|
||||
|
@ -223,15 +227,13 @@ pub struct GetPersonDetails {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub username: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_id: Option<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub saved_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_cursor: Option<ProfileCombinedPaginationCursor>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
@ -243,8 +245,7 @@ pub struct GetPersonDetailsResponse {
|
|||
pub person_view: PersonView,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub site: Option<Site>,
|
||||
pub comments: Vec<CommentView>,
|
||||
pub posts: Vec<PostView>,
|
||||
pub content: Vec<ProfileCombinedView>,
|
||||
pub moderates: Vec<CommunityModeratorView>,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,9 @@ use lemmy_api_common::{
|
|||
person::{GetPersonDetails, GetPersonDetailsResponse},
|
||||
utils::{check_private_instance, read_site_for_actor},
|
||||
};
|
||||
use lemmy_db_schema::{source::person::Person, utils::post_to_comment_sort_type};
|
||||
use lemmy_db_schema::source::person::Person;
|
||||
use lemmy_db_views::{
|
||||
comment_view::CommentQuery,
|
||||
post_view::PostQuery,
|
||||
profile_combined_view::ProfileCombinedQuery,
|
||||
structs::{LocalUserView, SiteView},
|
||||
};
|
||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
||||
|
@ -47,46 +46,38 @@ pub async fn read_person(
|
|||
// `my_user`
|
||||
let person_view = PersonView::read(&mut context.pool(), person_details_id).await?;
|
||||
|
||||
let sort = data.sort;
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let saved_only = data.saved_only;
|
||||
let community_id = data.community_id;
|
||||
// If its saved only, you don't care what creator it was
|
||||
// Or, if its not saved, then you only want it for that specific creator
|
||||
let creator_id = if !saved_only.unwrap_or_default() {
|
||||
Some(person_details_id)
|
||||
// parse pagination token
|
||||
let page_after = if let Some(pa) = &data.page_cursor {
|
||||
Some(pa.read(&mut context.pool()).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let page_back = data.page_back;
|
||||
let saved_only = data.saved_only;
|
||||
let community_id = data.community_id;
|
||||
|
||||
let local_user = local_user_view.as_ref().map(|l| &l.local_user);
|
||||
// If its saved only, then ignore the person details id,
|
||||
// and use your local user's id
|
||||
let creator_id = if !saved_only.unwrap_or_default() {
|
||||
Some(person_details_id)
|
||||
} else {
|
||||
local_user_view.as_ref().map(|u| u.local_user.person_id)
|
||||
};
|
||||
|
||||
let posts = PostQuery {
|
||||
sort,
|
||||
saved_only,
|
||||
local_user,
|
||||
community_id,
|
||||
page,
|
||||
limit,
|
||||
let content = if let Some(creator_id) = creator_id {
|
||||
ProfileCombinedQuery {
|
||||
creator_id,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
.await?;
|
||||
|
||||
let comments = CommentQuery {
|
||||
local_user,
|
||||
sort: sort.map(post_to_comment_sort_type),
|
||||
saved_only,
|
||||
community_id,
|
||||
page,
|
||||
limit,
|
||||
creator_id,
|
||||
..Default::default()
|
||||
saved_only,
|
||||
page_after,
|
||||
page_back,
|
||||
}
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
.await?;
|
||||
.list(&mut context.pool(), &local_user_view)
|
||||
.await?
|
||||
} else {
|
||||
// if the creator is missing (saved_only, and no local_user), then return empty content
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let moderates = CommunityModeratorView::for_person(
|
||||
&mut context.pool(),
|
||||
|
@ -97,12 +88,10 @@ pub async fn read_person(
|
|||
|
||||
let site = read_site_for_actor(person_view.person.actor_id.clone(), &context).await?;
|
||||
|
||||
// Return the jwt
|
||||
Ok(Json(GetPersonDetailsResponse {
|
||||
person_view,
|
||||
site,
|
||||
moderates,
|
||||
comments,
|
||||
posts,
|
||||
content,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -685,3 +685,31 @@ CALL r.create_report_combined_trigger ('comment_report');
|
|||
|
||||
CALL r.create_report_combined_trigger ('private_message_report');
|
||||
|
||||
-- Profile (comment, post)
|
||||
CREATE PROCEDURE r.create_profile_combined_trigger (table_name text)
|
||||
LANGUAGE plpgsql
|
||||
AS $a$
|
||||
BEGIN
|
||||
EXECUTE replace($b$ CREATE FUNCTION r.profile_combined_thing_insert ( )
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO profile_combined (published, thing_id)
|
||||
VALUES (NEW.published, NEW.id);
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
CREATE TRIGGER profile_combined
|
||||
AFTER INSERT ON thing
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION r.profile_combined_thing_insert ( );
|
||||
$b$,
|
||||
'thing',
|
||||
table_name);
|
||||
END;
|
||||
$a$;
|
||||
|
||||
CALL r.create_profile_combined_trigger ('post');
|
||||
|
||||
CALL r.create_profile_combined_trigger ('comment');
|
||||
|
||||
|
|
|
@ -18,14 +18,15 @@ use diesel::{
|
|||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
newtypes::CommunityId,
|
||||
aliases::creator_community_actions,
|
||||
newtypes::{CommunityId, PersonId},
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
comment_aggregates,
|
||||
community,
|
||||
community_actions,
|
||||
image_details,
|
||||
local_user,
|
||||
person,
|
||||
person_actions,
|
||||
|
@ -74,11 +75,11 @@ impl ProfileCombinedPaginationCursor {
|
|||
#[derive(Clone)]
|
||||
pub struct PaginationCursorData(ProfileCombined);
|
||||
|
||||
// TODO check these
|
||||
#[derive(Default)]
|
||||
pub struct ProfileCombinedQuery {
|
||||
pub creator_id: PersonId,
|
||||
pub community_id: Option<CommunityId>,
|
||||
pub unresolved_only: Option<bool>,
|
||||
pub saved_only: Option<bool>,
|
||||
pub page_after: Option<PaginationCursorData>,
|
||||
pub page_back: Option<bool>,
|
||||
}
|
||||
|
@ -87,10 +88,12 @@ impl ProfileCombinedQuery {
|
|||
pub async fn list(
|
||||
self,
|
||||
pool: &mut DbPool<'_>,
|
||||
user: &LocalUserView,
|
||||
user: &Option<LocalUserView>,
|
||||
) -> LemmyResult<Vec<ProfileCombinedView>> {
|
||||
let my_person_id = user.local_user.person_id;
|
||||
// let item_creator = aliases::person1.field(person::id);
|
||||
let my_person_id = user
|
||||
.as_ref()
|
||||
.map(|u| u.local_user.person_id)
|
||||
.unwrap_or(PersonId(-1));
|
||||
let item_creator = person::id;
|
||||
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
@ -114,20 +117,11 @@ impl ProfileCombinedQuery {
|
|||
// The item creator
|
||||
.inner_join(
|
||||
person::table.on(
|
||||
post::creator_id
|
||||
comment::creator_id
|
||||
.eq(person::id)
|
||||
.or(comment::creator_id.eq(person::id)),
|
||||
.or(post::creator_id.eq(person::id)),
|
||||
),
|
||||
)
|
||||
// The item creator
|
||||
// You can now use aliases::person1.field(person::id) / item_creator for all the item actions
|
||||
// .inner_join(
|
||||
// aliases::person1.on(
|
||||
// post::creator_id
|
||||
// .eq(item_creator)
|
||||
// .or(comment::creator_id.eq(item_creator)),
|
||||
// ),
|
||||
// )
|
||||
// The community
|
||||
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||
.left_join(actions_alias(
|
||||
|
@ -153,10 +147,7 @@ impl ProfileCombinedQuery {
|
|||
Some(my_person_id),
|
||||
item_creator,
|
||||
))
|
||||
.left_join(
|
||||
post_aggregates::table
|
||||
.on(profile_combined::post_id.eq(post_aggregates::post_id.nullable())),
|
||||
)
|
||||
.inner_join(post_aggregates::table.on(post::id.eq(post_aggregates::post_id)))
|
||||
.left_join(
|
||||
comment_aggregates::table
|
||||
.on(profile_combined::comment_id.eq(comment_aggregates::comment_id.nullable())),
|
||||
|
@ -166,43 +157,42 @@ impl ProfileCombinedQuery {
|
|||
Some(my_person_id),
|
||||
comment::id,
|
||||
))
|
||||
.left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())))
|
||||
// The creator id filter
|
||||
.filter(item_creator.eq(self.creator_id))
|
||||
.select((
|
||||
// Post-specific
|
||||
post::all_columns.nullable(),
|
||||
// post_aggregates::all_columns.nullable(),
|
||||
// coalesce(
|
||||
// post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
// post_aggregates::comments,
|
||||
// )
|
||||
// .nullable(),
|
||||
// post_actions::saved.nullable().is_not_null(),
|
||||
// post_actions::read.nullable().is_not_null(),
|
||||
// post_actions::hidden.nullable().is_not_null(),
|
||||
// post_actions::like_score.nullable(),
|
||||
// // Comment-specific
|
||||
// comment::all_columns.nullable(),
|
||||
// comment_aggregates::all_columns.nullable(),
|
||||
// comment_actions::saved.nullable().is_not_null(),
|
||||
// comment_actions::like_score.nullable(),
|
||||
// // Private-message-specific
|
||||
// private_message_profile::all_columns.nullable(),
|
||||
// private_message::all_columns.nullable(),
|
||||
// // Shared
|
||||
// person::all_columns,
|
||||
// aliases::person1.fields(person::all_columns),
|
||||
// community::all_columns.nullable(),
|
||||
// CommunityFollower::select_subscribed_type(),
|
||||
// aliases::person2.fields(person::all_columns.nullable()),
|
||||
// local_user::admin.nullable().is_not_null(),
|
||||
// creator_community_actions
|
||||
// .field(community_actions::received_ban)
|
||||
// .nullable()
|
||||
// .is_not_null(),
|
||||
// creator_community_actions
|
||||
// .field(community_actions::became_moderator)
|
||||
// .nullable()
|
||||
// .is_not_null(),
|
||||
// person_actions::blocked.nullable().is_not_null(),
|
||||
post_aggregates::all_columns,
|
||||
coalesce(
|
||||
post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
|
||||
post_aggregates::comments,
|
||||
),
|
||||
post_actions::saved.nullable().is_not_null(),
|
||||
post_actions::read.nullable().is_not_null(),
|
||||
post_actions::hidden.nullable().is_not_null(),
|
||||
post_actions::like_score.nullable(),
|
||||
image_details::all_columns.nullable(),
|
||||
// Comment-specific
|
||||
comment::all_columns.nullable(),
|
||||
comment_aggregates::all_columns.nullable(),
|
||||
comment_actions::saved.nullable().is_not_null(),
|
||||
comment_actions::like_score.nullable(),
|
||||
// Shared
|
||||
post::all_columns,
|
||||
community::all_columns,
|
||||
person::all_columns,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::received_ban)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
|
@ -210,9 +200,13 @@ impl ProfileCombinedQuery {
|
|||
query = query.filter(community::id.eq(community_id));
|
||||
}
|
||||
|
||||
// If its not an admin, get only the ones you mod
|
||||
if !user.local_user.admin {
|
||||
query = query.filter(community_actions::became_moderator.is_not_null());
|
||||
// If its saved only, then filter
|
||||
if self.saved_only.unwrap_or_default() {
|
||||
query = query.filter(
|
||||
comment_actions::saved
|
||||
.is_not_null()
|
||||
.or(post_actions::saved.is_not_null()),
|
||||
)
|
||||
}
|
||||
|
||||
let mut query = PaginatedQueryBuilder::new(query);
|
||||
|
@ -225,25 +219,11 @@ impl ProfileCombinedQuery {
|
|||
query = query.after(page_after);
|
||||
}
|
||||
|
||||
// If viewing all profiles, order by newest, but if viewing unresolved only, show the oldest
|
||||
// first (FIFO)
|
||||
if self.unresolved_only.unwrap_or_default() {
|
||||
// Sorting by published
|
||||
query = query
|
||||
.filter(
|
||||
post_profile::resolved
|
||||
.eq(false)
|
||||
.or(comment_profile::resolved.eq(false))
|
||||
.or(private_message_profile::resolved.eq(false)),
|
||||
)
|
||||
// TODO: when a `then_asc` method is added, use it here, make the id sort direction match,
|
||||
// and remove the separate index; unless additional columns are added to this sort
|
||||
.then_desc(ReverseTimestampKey(key::published));
|
||||
} else {
|
||||
query = query.then_desc(key::published);
|
||||
}
|
||||
|
||||
.then_desc(ReverseTimestampKey(key::published))
|
||||
// Tie breaker
|
||||
query = query.then_desc(key::id);
|
||||
.then_desc(key::id);
|
||||
|
||||
let res = query.load::<ProfileCombinedViewInternal>(conn).await?;
|
||||
|
||||
|
@ -259,14 +239,28 @@ fn map_to_enum(view: ProfileCombinedViewInternal) -> Option<ProfileCombinedView>
|
|||
// Use for a short alias
|
||||
let v = view;
|
||||
|
||||
if let (Some(post), Some(community), Some(unread_comments), Some(counts)) =
|
||||
(v.post, v.community, v.post_unread_comments, v.post_counts)
|
||||
{
|
||||
Some(ProfileCombinedView::Post(PostView {
|
||||
post,
|
||||
community,
|
||||
unread_comments,
|
||||
if let (Some(comment), Some(counts)) = (v.comment, v.comment_counts) {
|
||||
Some(ProfileCombinedView::Comment(CommentView {
|
||||
comment,
|
||||
counts,
|
||||
post: v.post,
|
||||
community: v.community,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
creator_is_admin: v.item_creator_is_admin,
|
||||
creator_blocked: v.item_creator_blocked,
|
||||
subscribed: v.subscribed,
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
}))
|
||||
} else {
|
||||
Some(ProfileCombinedView::Post(PostView {
|
||||
post: v.post,
|
||||
community: v.community,
|
||||
unread_comments: v.post_unread_comments,
|
||||
counts: v.post_counts,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
|
@ -277,28 +271,8 @@ fn map_to_enum(view: ProfileCombinedViewInternal) -> Option<ProfileCombinedView>
|
|||
read: v.post_read,
|
||||
hidden: v.post_hidden,
|
||||
my_vote: v.my_post_vote,
|
||||
image_details: v.image_details,
|
||||
banned_from_community: v.banned_from_community,
|
||||
}))
|
||||
} else if let (Some(comment), Some(counts), Some(post), Some(community)) = (
|
||||
v.comment,
|
||||
v.comment_counts,
|
||||
v.post.clone(),
|
||||
v.community.clone(),
|
||||
) {
|
||||
Some(ProfileCombinedView::Comment(CommentView {
|
||||
comment,
|
||||
counts,
|
||||
post,
|
||||
community,
|
||||
creator: v.item_creator,
|
||||
creator_banned_from_community: v.item_creator_banned_from_community,
|
||||
creator_is_moderator: v.item_creator_is_moderator,
|
||||
creator_is_admin: v.item_creator_is_admin,
|
||||
creator_blocked: v.item_creator_blocked,
|
||||
subscribed: v.subscribed,
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,8 +310,8 @@ pub struct ProfileCombinedViewInternal {
|
|||
pub my_post_vote: Option<i16>,
|
||||
pub image_details: Option<ImageDetails>,
|
||||
// Comment-specific
|
||||
pub comment: Comment,
|
||||
pub comment_counts: CommentAggregates,
|
||||
pub comment: Option<Comment>,
|
||||
pub comment_counts: Option<CommentAggregates>,
|
||||
pub comment_saved: bool,
|
||||
pub my_comment_vote: Option<i16>,
|
||||
// Shared
|
||||
|
@ -323,7 +323,6 @@ pub struct ProfileCombinedViewInternal {
|
|||
pub item_creator_is_moderator: bool,
|
||||
pub item_creator_banned_from_community: bool,
|
||||
pub item_creator_blocked: bool,
|
||||
pub item_saved: bool,
|
||||
pub banned_from_community: bool,
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
DROP TABLE profile_combined;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ CREATE TABLE profile_combined (
|
|||
id serial PRIMARY KEY,
|
||||
published timestamptz NOT NULL,
|
||||
post_id int UNIQUE REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
comment_id int UNIQUE REFERENCES comment ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
comment_id int UNIQUE REFERENCES COMMENT ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
-- Make sure only one of the columns is not null
|
||||
CHECK ((post_id IS NOT NULL)::integer + (comment_id IS NOT NULL)::integer = 1)
|
||||
);
|
||||
|
@ -27,3 +27,4 @@ SELECT
|
|||
id
|
||||
FROM
|
||||
comment;
|
||||
|
||||
|
|
Loading…
Reference in a new issue