Add support for Featured Posts (#2585)
* Add support for Featured Posts * Fix rebase * More fixes
This commit is contained in:
parent
0ecf256ce3
commit
9dfd819691
30 changed files with 319 additions and 156 deletions
|
@ -20,7 +20,7 @@
|
|||
"eslint": "^8.25.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"lemmy-js-client": "0.17.0-rc.48",
|
||||
"lemmy-js-client": "0.17.0-rc.56",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prettier": "^2.7.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
setupLogins,
|
||||
createPost,
|
||||
editPost,
|
||||
stickyPost,
|
||||
featurePost,
|
||||
lockPost,
|
||||
resolvePost,
|
||||
likePost,
|
||||
|
@ -157,8 +157,8 @@ test("Sticky a post", async () => {
|
|||
let betaPost1 = (
|
||||
await resolvePost(beta, postRes.post_view.post)
|
||||
).post.unwrap();
|
||||
let stickiedPostRes = await stickyPost(beta, true, betaPost1.post);
|
||||
expect(stickiedPostRes.post_view.post.stickied).toBe(true);
|
||||
let stickiedPostRes = await featurePost(beta, true, betaPost1.post);
|
||||
expect(stickiedPostRes.post_view.post.featured_community).toBe(true);
|
||||
|
||||
// Make sure that post is stickied on beta
|
||||
let betaPost = (
|
||||
|
@ -166,11 +166,11 @@ test("Sticky a post", async () => {
|
|||
).post.unwrap();
|
||||
expect(betaPost.community.local).toBe(true);
|
||||
expect(betaPost.creator.local).toBe(false);
|
||||
expect(betaPost.post.stickied).toBe(true);
|
||||
expect(betaPost.post.featured_community).toBe(true);
|
||||
|
||||
// Unsticky a post
|
||||
let unstickiedPost = await stickyPost(beta, false, betaPost1.post);
|
||||
expect(unstickiedPost.post_view.post.stickied).toBe(false);
|
||||
let unstickiedPost = await featurePost(beta, false, betaPost1.post);
|
||||
expect(unstickiedPost.post_view.post.featured_community).toBe(false);
|
||||
|
||||
// Make sure that post is unstickied on beta
|
||||
let betaPost2 = (
|
||||
|
@ -178,18 +178,18 @@ test("Sticky a post", async () => {
|
|||
).post.unwrap();
|
||||
expect(betaPost2.community.local).toBe(true);
|
||||
expect(betaPost2.creator.local).toBe(false);
|
||||
expect(betaPost2.post.stickied).toBe(false);
|
||||
expect(betaPost2.post.featured_community).toBe(false);
|
||||
|
||||
// Make sure that gamma cannot sticky the post on beta
|
||||
let gammaPost = (
|
||||
await resolvePost(gamma, postRes.post_view.post)
|
||||
).post.unwrap();
|
||||
let gammaTrySticky = await stickyPost(gamma, true, gammaPost.post);
|
||||
let gammaTrySticky = await featurePost(gamma, true, gammaPost.post);
|
||||
let betaPost3 = (
|
||||
await resolvePost(beta, postRes.post_view.post)
|
||||
).post.unwrap();
|
||||
expect(gammaTrySticky.post_view.post.stickied).toBe(true);
|
||||
expect(betaPost3.post.stickied).toBe(false);
|
||||
expect(gammaTrySticky.post_view.post.featured_community).toBe(true);
|
||||
expect(betaPost3.post.featured_community).toBe(false);
|
||||
});
|
||||
|
||||
test("Lock a post", async () => {
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
CreateComment,
|
||||
DeletePost,
|
||||
RemovePost,
|
||||
StickyPost,
|
||||
LockPost,
|
||||
PostResponse,
|
||||
SearchResponse,
|
||||
|
@ -64,6 +63,8 @@ import {
|
|||
CommentSortType,
|
||||
GetComments,
|
||||
GetCommentsResponse,
|
||||
FeaturePost,
|
||||
PostFeatureType,
|
||||
} from "lemmy-js-client";
|
||||
|
||||
export interface API {
|
||||
|
@ -180,14 +181,13 @@ export async function setupLogins() {
|
|||
rate_limit_search: Some(999),
|
||||
rate_limit_search_per_second: None,
|
||||
federation_enabled: None,
|
||||
federation_strict_allowlist: None,
|
||||
federation_http_fetch_retry_limit: None,
|
||||
federation_worker_count: None,
|
||||
captcha_enabled: None,
|
||||
captcha_difficulty: None,
|
||||
allowed_instances: None,
|
||||
blocked_instances: None,
|
||||
auth: "",
|
||||
taglines: None,
|
||||
});
|
||||
|
||||
// Set the blocks and auths for each
|
||||
|
@ -293,17 +293,18 @@ export async function removePost(
|
|||
return api.client.removePost(form);
|
||||
}
|
||||
|
||||
export async function stickyPost(
|
||||
export async function featurePost(
|
||||
api: API,
|
||||
stickied: boolean,
|
||||
featured: boolean,
|
||||
post: Post
|
||||
): Promise<PostResponse> {
|
||||
let form = new StickyPost({
|
||||
let form = new FeaturePost({
|
||||
post_id: post.id,
|
||||
stickied,
|
||||
featured,
|
||||
feature_type: PostFeatureType.Community,
|
||||
auth: api.auth.unwrap(),
|
||||
});
|
||||
return api.client.stickyPost(form);
|
||||
return api.client.featurePost(form);
|
||||
}
|
||||
|
||||
export async function lockPost(
|
||||
|
|
|
@ -2373,10 +2373,15 @@ kleur@^3.0.3:
|
|||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
lemmy-js-client@0.17.0-rc.48:
|
||||
version "0.17.0-rc.48"
|
||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.48.tgz#6085812d4901b7d12b3fca237d8aced7f5210eac"
|
||||
integrity sha512-Lz8Nzq/kczQtDj6STlbhxoEarFHtTCoWcWBabyPs6X6em/pfK/cnZqx1mMn7EaBSDUVQ+WL8UNFjQiqjhR4kww==
|
||||
lemmy-js-client@0.17.0-rc.56:
|
||||
version "0.17.0-rc.56"
|
||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.56.tgz#2c7abba9b8195826eb36401e7c5c2cb75609bcf2"
|
||||
integrity sha512-7MM5xV8H9fIr1TbM/4e9PFKJpwlD2t135pSiH92TFgdkTzOMf0mtLO2BWLAQ7Rq+XVoVgj/WSBR4BofJka8XRQ==
|
||||
dependencies:
|
||||
"@sniptt/monads" "^0.5.10"
|
||||
class-transformer "^0.5.1"
|
||||
node-fetch "2.6.6"
|
||||
reflect-metadata "^0.1.13"
|
||||
|
||||
leven@^3.1.0:
|
||||
version "3.1.0"
|
||||
|
@ -2511,6 +2516,13 @@ natural-compare@^1.4.0:
|
|||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
node-fetch@2.6.6:
|
||||
version "2.6.6"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89"
|
||||
integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.1:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
|
|
|
@ -2,26 +2,28 @@ use crate::Perform;
|
|||
use actix_web::web::Data;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
post::{PostResponse, StickyPost},
|
||||
post::{FeaturePost, PostResponse},
|
||||
utils::{
|
||||
check_community_ban,
|
||||
check_community_deleted_or_removed,
|
||||
get_local_user_view_from_jwt,
|
||||
is_admin,
|
||||
is_mod_or_admin,
|
||||
},
|
||||
websocket::{send::send_post_ws_message, UserOperation},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
moderator::{ModStickyPost, ModStickyPostForm},
|
||||
moderator::{ModFeaturePost, ModFeaturePostForm},
|
||||
post::{Post, PostUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
PostFeatureType,
|
||||
};
|
||||
use lemmy_utils::{error::LemmyError, ConnectionId};
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl Perform for StickyPost {
|
||||
impl Perform for FeaturePost {
|
||||
type Response = PostResponse;
|
||||
|
||||
#[tracing::instrument(skip(context, websocket_id))]
|
||||
|
@ -30,7 +32,7 @@ impl Perform for StickyPost {
|
|||
context: &Data<LemmyContext>,
|
||||
websocket_id: Option<ConnectionId>,
|
||||
) -> Result<PostResponse, LemmyError> {
|
||||
let data: &StickyPost = self;
|
||||
let data: &FeaturePost = self;
|
||||
let local_user_view =
|
||||
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
|
||||
|
||||
|
@ -45,36 +47,44 @@ impl Perform for StickyPost {
|
|||
.await?;
|
||||
check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?;
|
||||
|
||||
// Verify that only the mods can sticky
|
||||
is_mod_or_admin(
|
||||
context.pool(),
|
||||
local_user_view.person.id,
|
||||
orig_post.community_id,
|
||||
)
|
||||
.await?;
|
||||
if data.feature_type == PostFeatureType::Community {
|
||||
// Verify that only the mods can feature in community
|
||||
is_mod_or_admin(
|
||||
context.pool(),
|
||||
local_user_view.person.id,
|
||||
orig_post.community_id,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
is_admin(&local_user_view)?;
|
||||
}
|
||||
|
||||
// Update the post
|
||||
let post_id = data.post_id;
|
||||
let stickied = data.stickied;
|
||||
Post::update(
|
||||
context.pool(),
|
||||
post_id,
|
||||
&PostUpdateForm::builder().stickied(Some(stickied)).build(),
|
||||
)
|
||||
.await?;
|
||||
let new_post: PostUpdateForm = if data.feature_type == PostFeatureType::Community {
|
||||
PostUpdateForm::builder()
|
||||
.featured_community(Some(data.featured))
|
||||
.build()
|
||||
} else {
|
||||
PostUpdateForm::builder()
|
||||
.featured_local(Some(data.featured))
|
||||
.build()
|
||||
};
|
||||
Post::update(context.pool(), post_id, &new_post).await?;
|
||||
|
||||
// Mod tables
|
||||
let form = ModStickyPostForm {
|
||||
let form = ModFeaturePostForm {
|
||||
mod_person_id: local_user_view.person.id,
|
||||
post_id: data.post_id,
|
||||
stickied: Some(stickied),
|
||||
featured: data.featured,
|
||||
is_featured_community: data.feature_type == PostFeatureType::Community,
|
||||
};
|
||||
|
||||
ModStickyPost::create(context.pool(), &form).await?;
|
||||
ModFeaturePost::create(context.pool(), &form).await?;
|
||||
|
||||
send_post_ws_message(
|
||||
data.post_id,
|
||||
UserOperation::StickyPost,
|
||||
UserOperation::FeaturePost,
|
||||
websocket_id,
|
||||
Some(local_user_view.person.id),
|
||||
context,
|
|
@ -1,6 +1,6 @@
|
|||
mod feature;
|
||||
mod get_link_metadata;
|
||||
mod like;
|
||||
mod lock;
|
||||
mod mark_read;
|
||||
mod save;
|
||||
mod sticky;
|
||||
|
|
|
@ -19,12 +19,12 @@ use lemmy_db_views_moderator::structs::{
|
|||
ModAddView,
|
||||
ModBanFromCommunityView,
|
||||
ModBanView,
|
||||
ModFeaturePostView,
|
||||
ModHideCommunityView,
|
||||
ModLockPostView,
|
||||
ModRemoveCommentView,
|
||||
ModRemoveCommunityView,
|
||||
ModRemovePostView,
|
||||
ModStickyPostView,
|
||||
ModTransferCommunityView,
|
||||
ModlogListParams,
|
||||
};
|
||||
|
@ -91,8 +91,8 @@ impl Perform for GetModlog {
|
|||
_ => Default::default(),
|
||||
};
|
||||
|
||||
let stickied_posts = match type_ {
|
||||
All | ModStickyPost => ModStickyPostView::list(context.pool(), params).await?,
|
||||
let featured_posts = match type_ {
|
||||
All | ModFeaturePost => ModFeaturePostView::list(context.pool(), params).await?,
|
||||
_ => Default::default(),
|
||||
};
|
||||
|
||||
|
@ -181,7 +181,7 @@ impl Perform for GetModlog {
|
|||
Ok(GetModlogResponse {
|
||||
removed_posts,
|
||||
locked_posts,
|
||||
stickied_posts,
|
||||
featured_posts,
|
||||
removed_comments,
|
||||
removed_communities,
|
||||
banned_from_community,
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::sensitive::Sensitive;
|
|||
use lemmy_db_schema::{
|
||||
newtypes::{CommentId, CommunityId, DbUrl, LanguageId, PostId, PostReportId},
|
||||
ListingType,
|
||||
PostFeatureType,
|
||||
SortType,
|
||||
};
|
||||
use lemmy_db_views::structs::{PostReportView, PostView};
|
||||
|
@ -106,9 +107,10 @@ pub struct LockPost {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
pub struct StickyPost {
|
||||
pub struct FeaturePost {
|
||||
pub post_id: PostId,
|
||||
pub stickied: bool,
|
||||
pub featured: bool,
|
||||
pub feature_type: PostFeatureType,
|
||||
pub auth: Sensitive<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,12 @@ use lemmy_db_views_moderator::structs::{
|
|||
ModAddView,
|
||||
ModBanFromCommunityView,
|
||||
ModBanView,
|
||||
ModFeaturePostView,
|
||||
ModHideCommunityView,
|
||||
ModLockPostView,
|
||||
ModRemoveCommentView,
|
||||
ModRemoveCommunityView,
|
||||
ModRemovePostView,
|
||||
ModStickyPostView,
|
||||
ModTransferCommunityView,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -93,7 +93,7 @@ pub struct GetModlog {
|
|||
pub struct GetModlogResponse {
|
||||
pub removed_posts: Vec<ModRemovePostView>,
|
||||
pub locked_posts: Vec<ModLockPostView>,
|
||||
pub stickied_posts: Vec<ModStickyPostView>,
|
||||
pub featured_posts: Vec<ModFeaturePostView>,
|
||||
pub removed_comments: Vec<ModRemoveCommentView>,
|
||||
pub removed_communities: Vec<ModRemoveCommunityView>,
|
||||
pub banned_from_community: Vec<ModBanFromCommunityView>,
|
||||
|
|
|
@ -38,7 +38,7 @@ pub enum UserOperation {
|
|||
ListCommentReports,
|
||||
CreatePostLike,
|
||||
LockPost,
|
||||
StickyPost,
|
||||
FeaturePost,
|
||||
MarkPostAsRead,
|
||||
SavePost,
|
||||
CreatePostReport,
|
||||
|
|
|
@ -25,7 +25,7 @@ use activitypub_federation::{
|
|||
use activitystreams_kinds::public;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
post::{CreatePost, EditPost, LockPost, PostResponse, StickyPost},
|
||||
post::{CreatePost, EditPost, FeaturePost, LockPost, PostResponse},
|
||||
utils::get_local_user_view_from_jwt,
|
||||
websocket::{send::send_post_ws_message, UserOperationCrud},
|
||||
};
|
||||
|
@ -101,7 +101,7 @@ impl SendActivity for LockPost {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl SendActivity for StickyPost {
|
||||
impl SendActivity for FeaturePost {
|
||||
type Response = PostResponse;
|
||||
|
||||
async fn send_activity(
|
||||
|
@ -205,9 +205,9 @@ impl ActivityHandler for CreateOrUpdatePage {
|
|||
// However, when fetching a remote post we generate a new create activity with the current
|
||||
// locked/stickied value, so this check may fail. So only check if its a local community,
|
||||
// because then we will definitely receive all create and update activities separately.
|
||||
let is_stickied_or_locked =
|
||||
let is_featured_or_locked =
|
||||
self.object.stickied == Some(true) || self.object.comments_enabled == Some(false);
|
||||
if community.local && is_stickied_or_locked {
|
||||
if community.local && is_featured_or_locked {
|
||||
return Err(LemmyError::from_message(
|
||||
"New post cannot be stickied or locked",
|
||||
));
|
||||
|
|
|
@ -32,7 +32,7 @@ use lemmy_db_schema::{
|
|||
source::{
|
||||
community::Community,
|
||||
local_site::LocalSite,
|
||||
moderator::{ModLockPost, ModLockPostForm, ModStickyPost, ModStickyPostForm},
|
||||
moderator::{ModFeaturePost, ModFeaturePostForm, ModLockPost, ModLockPostForm},
|
||||
person::Person,
|
||||
post::{Post, PostInsertForm, PostUpdateForm},
|
||||
},
|
||||
|
@ -116,7 +116,7 @@ impl ApubObject for ApubPost {
|
|||
image: self.thumbnail_url.clone().map(ImageObject::new),
|
||||
comments_enabled: Some(!self.locked),
|
||||
sensitive: Some(self.nsfw),
|
||||
stickied: Some(self.stickied),
|
||||
stickied: Some(self.featured_community),
|
||||
language,
|
||||
published: Some(convert_datetime(self.published)),
|
||||
updated: self.updated.map(convert_datetime),
|
||||
|
@ -208,7 +208,6 @@ impl ApubObject for ApubPost {
|
|||
updated: page.updated.map(|u| u.naive_local()),
|
||||
deleted: Some(false),
|
||||
nsfw: page.sensitive,
|
||||
stickied: page.stickied,
|
||||
embed_title,
|
||||
embed_description,
|
||||
embed_video_url,
|
||||
|
@ -216,6 +215,8 @@ impl ApubObject for ApubPost {
|
|||
ap_id: Some(page.id.clone().into()),
|
||||
local: Some(false),
|
||||
language_id,
|
||||
featured_community: page.stickied,
|
||||
featured_local: None,
|
||||
}
|
||||
} else {
|
||||
// if is mod action, only update locked/stickied fields, nothing else
|
||||
|
@ -225,7 +226,7 @@ impl ApubObject for ApubPost {
|
|||
.community_id(community.id)
|
||||
.ap_id(Some(page.id.clone().into()))
|
||||
.locked(page.comments_enabled.map(|e| !e))
|
||||
.stickied(page.stickied)
|
||||
.featured_community(page.stickied)
|
||||
.updated(page.updated.map(|u| u.naive_local()))
|
||||
.build()
|
||||
};
|
||||
|
@ -236,14 +237,15 @@ impl ApubObject for ApubPost {
|
|||
|
||||
let post = Post::create(context.pool(), &form).await?;
|
||||
|
||||
// write mod log entries for sticky/lock
|
||||
if Page::is_stickied_changed(&old_post, &page.stickied) {
|
||||
let form = ModStickyPostForm {
|
||||
// write mod log entries for feature/lock
|
||||
if Page::is_featured_changed(&old_post, &page.stickied) {
|
||||
let form = ModFeaturePostForm {
|
||||
mod_person_id: creator.id,
|
||||
post_id: post.id,
|
||||
stickied: Some(post.stickied),
|
||||
featured: post.featured_community,
|
||||
is_featured_community: true,
|
||||
};
|
||||
ModStickyPost::create(context.pool(), &form).await?;
|
||||
ModFeaturePost::create(context.pool(), &form).await?;
|
||||
}
|
||||
if Page::is_locked_changed(&old_post, &page.comments_enabled) {
|
||||
let form = ModLockPostForm {
|
||||
|
@ -295,7 +297,7 @@ mod tests {
|
|||
assert!(post.body.is_some());
|
||||
assert_eq!(post.body.as_ref().unwrap().len(), 45);
|
||||
assert!(!post.locked);
|
||||
assert!(post.stickied);
|
||||
assert!(post.featured_community);
|
||||
assert_eq!(request_counter, 0);
|
||||
|
||||
Post::delete(context.pool(), post.id).await.unwrap();
|
||||
|
|
|
@ -137,18 +137,18 @@ impl Page {
|
|||
.dereference_local(context)
|
||||
.await;
|
||||
|
||||
let stickied_changed = Page::is_stickied_changed(&old_post, &self.stickied);
|
||||
let featured_changed = Page::is_featured_changed(&old_post, &self.stickied);
|
||||
let locked_changed = Page::is_locked_changed(&old_post, &self.comments_enabled);
|
||||
Ok(stickied_changed || locked_changed)
|
||||
Ok(featured_changed || locked_changed)
|
||||
}
|
||||
|
||||
pub(crate) fn is_stickied_changed<E>(
|
||||
pub(crate) fn is_featured_changed<E>(
|
||||
old_post: &Result<ApubPost, E>,
|
||||
new_stickied: &Option<bool>,
|
||||
new_featured_community: &Option<bool>,
|
||||
) -> bool {
|
||||
if let Some(new_stickied) = new_stickied {
|
||||
if let Some(new_featured_community) = new_featured_community {
|
||||
if let Ok(old_post) = old_post {
|
||||
return new_stickied != &old_post.stickied;
|
||||
return new_featured_community != &old_post.featured_community;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,11 @@ pub struct PostAggregates {
|
|||
pub score: i64,
|
||||
pub upvotes: i64,
|
||||
pub downvotes: i64,
|
||||
pub stickied: bool,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
pub newest_comment_time_necro: chrono::NaiveDateTime, // A newest comment time, limited to 2 days, to prevent necrobumping
|
||||
pub newest_comment_time: chrono::NaiveDateTime,
|
||||
pub featured_community: bool,
|
||||
pub featured_local: bool,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -16,6 +16,8 @@ use crate::{
|
|||
ModBanForm,
|
||||
ModBanFromCommunity,
|
||||
ModBanFromCommunityForm,
|
||||
ModFeaturePost,
|
||||
ModFeaturePostForm,
|
||||
ModHideCommunity,
|
||||
ModHideCommunityForm,
|
||||
ModLockPost,
|
||||
|
@ -26,8 +28,6 @@ use crate::{
|
|||
ModRemoveCommunityForm,
|
||||
ModRemovePost,
|
||||
ModRemovePostForm,
|
||||
ModStickyPost,
|
||||
ModStickyPostForm,
|
||||
ModTransferCommunity,
|
||||
ModTransferCommunityForm,
|
||||
},
|
||||
|
@ -98,29 +98,29 @@ impl Crud for ModLockPost {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for ModStickyPost {
|
||||
type InsertForm = ModStickyPostForm;
|
||||
type UpdateForm = ModStickyPostForm;
|
||||
impl Crud for ModFeaturePost {
|
||||
type InsertForm = ModFeaturePostForm;
|
||||
type UpdateForm = ModFeaturePostForm;
|
||||
type IdType = i32;
|
||||
async fn read(pool: &DbPool, from_id: i32) -> Result<Self, Error> {
|
||||
use crate::schema::mod_sticky_post::dsl::mod_sticky_post;
|
||||
use crate::schema::mod_feature_post::dsl::mod_feature_post;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
mod_sticky_post.find(from_id).first::<Self>(conn).await
|
||||
mod_feature_post.find(from_id).first::<Self>(conn).await
|
||||
}
|
||||
|
||||
async fn create(pool: &DbPool, form: &ModStickyPostForm) -> Result<Self, Error> {
|
||||
use crate::schema::mod_sticky_post::dsl::mod_sticky_post;
|
||||
async fn create(pool: &DbPool, form: &ModFeaturePostForm) -> Result<Self, Error> {
|
||||
use crate::schema::mod_feature_post::dsl::mod_feature_post;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
insert_into(mod_sticky_post)
|
||||
insert_into(mod_feature_post)
|
||||
.values(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update(pool: &DbPool, from_id: i32, form: &ModStickyPostForm) -> Result<Self, Error> {
|
||||
use crate::schema::mod_sticky_post::dsl::mod_sticky_post;
|
||||
async fn update(pool: &DbPool, from_id: i32, form: &ModFeaturePostForm) -> Result<Self, Error> {
|
||||
use crate::schema::mod_feature_post::dsl::mod_feature_post;
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(mod_sticky_post.find(from_id))
|
||||
diesel::update(mod_feature_post.find(from_id))
|
||||
.set(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
|
@ -525,6 +525,8 @@ mod tests {
|
|||
ModBanForm,
|
||||
ModBanFromCommunity,
|
||||
ModBanFromCommunityForm,
|
||||
ModFeaturePost,
|
||||
ModFeaturePostForm,
|
||||
ModLockPost,
|
||||
ModLockPostForm,
|
||||
ModRemoveComment,
|
||||
|
@ -533,8 +535,6 @@ mod tests {
|
|||
ModRemoveCommunityForm,
|
||||
ModRemovePost,
|
||||
ModRemovePostForm,
|
||||
ModStickyPost,
|
||||
ModStickyPostForm,
|
||||
},
|
||||
person::{Person, PersonInsertForm},
|
||||
post::{Post, PostInsertForm},
|
||||
|
@ -637,25 +637,27 @@ mod tests {
|
|||
when_: inserted_mod_lock_post.when_,
|
||||
};
|
||||
|
||||
// sticky post
|
||||
// feature post
|
||||
|
||||
let mod_sticky_post_form = ModStickyPostForm {
|
||||
let mod_feature_post_form = ModFeaturePostForm {
|
||||
mod_person_id: inserted_mod.id,
|
||||
post_id: inserted_post.id,
|
||||
stickied: None,
|
||||
featured: false,
|
||||
is_featured_community: true,
|
||||
};
|
||||
let inserted_mod_sticky_post = ModStickyPost::create(pool, &mod_sticky_post_form)
|
||||
let inserted_mod_feature_post = ModFeaturePost::create(pool, &mod_feature_post_form)
|
||||
.await
|
||||
.unwrap();
|
||||
let read_mod_sticky_post = ModStickyPost::read(pool, inserted_mod_sticky_post.id)
|
||||
let read_mod_feature_post = ModFeaturePost::read(pool, inserted_mod_feature_post.id)
|
||||
.await
|
||||
.unwrap();
|
||||
let expected_mod_sticky_post = ModStickyPost {
|
||||
id: inserted_mod_sticky_post.id,
|
||||
let expected_mod_feature_post = ModFeaturePost {
|
||||
id: inserted_mod_feature_post.id,
|
||||
post_id: inserted_post.id,
|
||||
mod_person_id: inserted_mod.id,
|
||||
stickied: Some(true),
|
||||
when_: inserted_mod_sticky_post.when_,
|
||||
featured: false,
|
||||
is_featured_community: true,
|
||||
when_: inserted_mod_feature_post.when_,
|
||||
};
|
||||
|
||||
// comment
|
||||
|
@ -809,7 +811,7 @@ mod tests {
|
|||
|
||||
assert_eq!(expected_mod_remove_post, read_mod_remove_post);
|
||||
assert_eq!(expected_mod_lock_post, read_mod_lock_post);
|
||||
assert_eq!(expected_mod_sticky_post, read_mod_sticky_post);
|
||||
assert_eq!(expected_mod_feature_post, read_mod_feature_post);
|
||||
assert_eq!(expected_mod_remove_comment, read_mod_remove_comment);
|
||||
assert_eq!(expected_mod_remove_community, read_mod_remove_community);
|
||||
assert_eq!(expected_mod_ban_from_community, read_mod_ban_from_community);
|
||||
|
|
|
@ -6,11 +6,11 @@ use crate::{
|
|||
community_id,
|
||||
creator_id,
|
||||
deleted,
|
||||
featured_community,
|
||||
name,
|
||||
post,
|
||||
published,
|
||||
removed,
|
||||
stickied,
|
||||
thumbnail_url,
|
||||
updated,
|
||||
url,
|
||||
|
@ -83,7 +83,7 @@ impl Post {
|
|||
.filter(deleted.eq(false))
|
||||
.filter(removed.eq(false))
|
||||
.then_order_by(published.desc())
|
||||
.then_order_by(stickied.desc())
|
||||
.then_order_by(featured_community.desc())
|
||||
.limit(FETCH_LIMIT_MAX)
|
||||
.load::<Self>(conn)
|
||||
.await
|
||||
|
@ -381,7 +381,6 @@ mod tests {
|
|||
published: inserted_post.published,
|
||||
removed: false,
|
||||
locked: false,
|
||||
stickied: false,
|
||||
nsfw: false,
|
||||
deleted: false,
|
||||
updated: None,
|
||||
|
@ -392,6 +391,8 @@ mod tests {
|
|||
ap_id: inserted_post.ap_id.clone(),
|
||||
local: true,
|
||||
language_id: Default::default(),
|
||||
featured_community: false,
|
||||
featured_local: false,
|
||||
};
|
||||
|
||||
// Post Like
|
||||
|
|
|
@ -82,7 +82,7 @@ pub enum ModlogActionType {
|
|||
All,
|
||||
ModRemovePost,
|
||||
ModLockPost,
|
||||
ModStickyPost,
|
||||
ModFeaturePost,
|
||||
ModRemoveComment,
|
||||
ModRemoveCommunity,
|
||||
ModBanFromCommunity,
|
||||
|
@ -96,3 +96,12 @@ pub enum ModlogActionType {
|
|||
AdminPurgePost,
|
||||
AdminPurgeComment,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq,
|
||||
)]
|
||||
pub enum PostFeatureType {
|
||||
#[default]
|
||||
Local,
|
||||
Community,
|
||||
}
|
||||
|
|
|
@ -273,12 +273,13 @@ table! {
|
|||
}
|
||||
|
||||
table! {
|
||||
mod_sticky_post (id) {
|
||||
mod_feature_post (id) {
|
||||
id -> Int4,
|
||||
mod_person_id -> Int4,
|
||||
post_id -> Int4,
|
||||
stickied -> Nullable<Bool>,
|
||||
featured -> Bool,
|
||||
when_ -> Timestamp,
|
||||
is_featured_community -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +372,6 @@ table! {
|
|||
updated -> Nullable<Timestamp>,
|
||||
deleted -> Bool,
|
||||
nsfw -> Bool,
|
||||
stickied -> Bool,
|
||||
embed_title -> Nullable<Text>,
|
||||
embed_description -> Nullable<Text>,
|
||||
embed_video_url -> Nullable<Text>,
|
||||
|
@ -379,6 +379,8 @@ table! {
|
|||
ap_id -> Varchar,
|
||||
local -> Bool,
|
||||
language_id -> Int4,
|
||||
featured_community -> Bool,
|
||||
featured_local -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,10 +402,11 @@ table! {
|
|||
score -> Int8,
|
||||
upvotes -> Int8,
|
||||
downvotes -> Int8,
|
||||
stickied -> Bool,
|
||||
published -> Timestamp,
|
||||
newest_comment_time_necro -> Timestamp,
|
||||
newest_comment_time -> Timestamp,
|
||||
featured_community -> Bool,
|
||||
featured_local -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,8 +774,8 @@ joinable!(mod_remove_community -> community (community_id));
|
|||
joinable!(mod_remove_community -> person (mod_person_id));
|
||||
joinable!(mod_remove_post -> person (mod_person_id));
|
||||
joinable!(mod_remove_post -> post (post_id));
|
||||
joinable!(mod_sticky_post -> person (mod_person_id));
|
||||
joinable!(mod_sticky_post -> post (post_id));
|
||||
joinable!(mod_feature_post -> person (mod_person_id));
|
||||
joinable!(mod_feature_post -> post (post_id));
|
||||
joinable!(password_reset_request -> local_user (local_user_id));
|
||||
joinable!(person_aggregates -> person (person_id));
|
||||
joinable!(person_ban -> person (person_id));
|
||||
|
@ -848,7 +851,7 @@ allow_tables_to_appear_in_same_query!(
|
|||
mod_remove_comment,
|
||||
mod_remove_community,
|
||||
mod_remove_post,
|
||||
mod_sticky_post,
|
||||
mod_feature_post,
|
||||
mod_hide_community,
|
||||
password_reset_request,
|
||||
person,
|
||||
|
|
|
@ -9,12 +9,12 @@ use crate::schema::{
|
|||
mod_add_community,
|
||||
mod_ban,
|
||||
mod_ban_from_community,
|
||||
mod_feature_post,
|
||||
mod_hide_community,
|
||||
mod_lock_post,
|
||||
mod_remove_comment,
|
||||
mod_remove_community,
|
||||
mod_remove_post,
|
||||
mod_sticky_post,
|
||||
mod_transfer_community,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -61,21 +61,23 @@ pub struct ModLockPostForm {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = mod_sticky_post))]
|
||||
pub struct ModStickyPost {
|
||||
#[cfg_attr(feature = "full", diesel(table_name = mod_feature_post))]
|
||||
pub struct ModFeaturePost {
|
||||
pub id: i32,
|
||||
pub mod_person_id: PersonId,
|
||||
pub post_id: PostId,
|
||||
pub stickied: Option<bool>,
|
||||
pub featured: bool,
|
||||
pub when_: chrono::NaiveDateTime,
|
||||
pub is_featured_community: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = mod_sticky_post))]
|
||||
pub struct ModStickyPostForm {
|
||||
#[cfg_attr(feature = "full", diesel(table_name = mod_feature_post))]
|
||||
pub struct ModFeaturePostForm {
|
||||
pub mod_person_id: PersonId,
|
||||
pub post_id: PostId,
|
||||
pub stickied: Option<bool>,
|
||||
pub featured: bool,
|
||||
pub is_featured_community: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
|
|
|
@ -20,7 +20,6 @@ pub struct Post {
|
|||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: bool,
|
||||
pub nsfw: bool,
|
||||
pub stickied: bool,
|
||||
pub embed_title: Option<String>,
|
||||
pub embed_description: Option<String>,
|
||||
pub embed_video_url: Option<DbUrl>,
|
||||
|
@ -28,6 +27,8 @@ pub struct Post {
|
|||
pub ap_id: DbUrl,
|
||||
pub local: bool,
|
||||
pub language_id: LanguageId,
|
||||
pub featured_community: bool,
|
||||
pub featured_local: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, TypedBuilder)]
|
||||
|
@ -49,7 +50,6 @@ pub struct PostInsertForm {
|
|||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub published: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: Option<bool>,
|
||||
pub stickied: Option<bool>,
|
||||
pub embed_title: Option<String>,
|
||||
pub embed_description: Option<String>,
|
||||
pub embed_video_url: Option<DbUrl>,
|
||||
|
@ -57,6 +57,8 @@ pub struct PostInsertForm {
|
|||
pub ap_id: Option<DbUrl>,
|
||||
pub local: Option<bool>,
|
||||
pub language_id: Option<LanguageId>,
|
||||
pub featured_community: Option<bool>,
|
||||
pub featured_local: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, TypedBuilder)]
|
||||
|
@ -73,7 +75,6 @@ pub struct PostUpdateForm {
|
|||
pub published: Option<chrono::NaiveDateTime>,
|
||||
pub updated: Option<Option<chrono::NaiveDateTime>>,
|
||||
pub deleted: Option<bool>,
|
||||
pub stickied: Option<bool>,
|
||||
pub embed_title: Option<Option<String>>,
|
||||
pub embed_description: Option<Option<String>>,
|
||||
pub embed_video_url: Option<Option<DbUrl>>,
|
||||
|
@ -81,6 +82,8 @@ pub struct PostUpdateForm {
|
|||
pub ap_id: Option<DbUrl>,
|
||||
pub local: Option<bool>,
|
||||
pub language_id: Option<LanguageId>,
|
||||
pub featured_community: Option<bool>,
|
||||
pub featured_local: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
|
|
|
@ -863,7 +863,6 @@ mod tests {
|
|||
removed: false,
|
||||
deleted: false,
|
||||
locked: false,
|
||||
stickied: false,
|
||||
nsfw: false,
|
||||
embed_title: None,
|
||||
embed_description: None,
|
||||
|
@ -872,6 +871,8 @@ mod tests {
|
|||
ap_id: data.inserted_post.ap_id.clone(),
|
||||
local: true,
|
||||
language_id: Default::default(),
|
||||
featured_community: false,
|
||||
featured_local: false,
|
||||
},
|
||||
community: CommunitySafe {
|
||||
id: data.inserted_community.id,
|
||||
|
|
|
@ -469,10 +469,11 @@ mod tests {
|
|||
score: 0,
|
||||
upvotes: 0,
|
||||
downvotes: 0,
|
||||
stickied: false,
|
||||
published: agg.published,
|
||||
newest_comment_time_necro: inserted_post.published,
|
||||
newest_comment_time: inserted_post.published,
|
||||
featured_community: false,
|
||||
featured_local: false,
|
||||
},
|
||||
resolver: None,
|
||||
};
|
||||
|
|
|
@ -324,17 +324,16 @@ impl<'a> PostQuery<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(community_id) = self.community_id {
|
||||
if self.community_id.is_none() && self.community_actor_id.is_none() {
|
||||
query = query.then_order_by(post_aggregates::featured_local.desc());
|
||||
} else if let Some(community_id) = self.community_id {
|
||||
query = query
|
||||
.filter(post::community_id.eq(community_id))
|
||||
.then_order_by(post_aggregates::stickied.desc());
|
||||
}
|
||||
|
||||
if let Some(community_actor_id) = self.community_actor_id {
|
||||
.then_order_by(post_aggregates::featured_community.desc());
|
||||
} else if let Some(community_actor_id) = self.community_actor_id {
|
||||
query = query
|
||||
.filter(community::actor_id.eq(community_actor_id))
|
||||
.then_order_by(post_aggregates::stickied.desc());
|
||||
.then_order_by(post_aggregates::featured_community.desc());
|
||||
}
|
||||
|
||||
if let Some(url_search) = self.url_search {
|
||||
|
@ -860,7 +859,6 @@ mod tests {
|
|||
removed: false,
|
||||
deleted: false,
|
||||
locked: false,
|
||||
stickied: false,
|
||||
nsfw: false,
|
||||
embed_title: None,
|
||||
embed_description: None,
|
||||
|
@ -869,6 +867,8 @@ mod tests {
|
|||
ap_id: inserted_post.ap_id.clone(),
|
||||
local: true,
|
||||
language_id: LanguageId(47),
|
||||
featured_community: false,
|
||||
featured_local: false,
|
||||
},
|
||||
my_vote: None,
|
||||
unread_comments: 0,
|
||||
|
@ -919,10 +919,11 @@ mod tests {
|
|||
score: 0,
|
||||
upvotes: 0,
|
||||
downvotes: 0,
|
||||
stickied: false,
|
||||
published: agg.published,
|
||||
newest_comment_time_necro: inserted_post.published,
|
||||
newest_comment_time: inserted_post.published,
|
||||
featured_community: false,
|
||||
featured_local: false,
|
||||
},
|
||||
subscribed: SubscribedType::NotSubscribed,
|
||||
read: false,
|
||||
|
|
|
@ -15,6 +15,8 @@ pub mod mod_ban_from_community_view;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod mod_ban_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod mod_feature_post_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod mod_hide_community_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod mod_lock_post_view;
|
||||
|
@ -25,7 +27,5 @@ pub mod mod_remove_community_view;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod mod_remove_post_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod mod_sticky_post_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod mod_transfer_community_view;
|
||||
pub mod structs;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::structs::{ModStickyPostView, ModlogListParams};
|
||||
use crate::structs::{ModFeaturePostView, ModlogListParams};
|
||||
use diesel::{
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
|
@ -11,10 +11,10 @@ use diesel::{
|
|||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PersonId,
|
||||
schema::{community, mod_sticky_post, person, post},
|
||||
schema::{community, mod_feature_post, person, post},
|
||||
source::{
|
||||
community::{Community, CommunitySafe},
|
||||
moderator::ModStickyPost,
|
||||
moderator::ModFeaturePost,
|
||||
person::{Person, PersonSafe},
|
||||
post::Post,
|
||||
},
|
||||
|
@ -22,9 +22,9 @@ use lemmy_db_schema::{
|
|||
utils::{get_conn, limit_and_offset, DbPool},
|
||||
};
|
||||
|
||||
type ModStickyPostViewTuple = (ModStickyPost, Option<PersonSafe>, Post, CommunitySafe);
|
||||
type ModFeaturePostViewTuple = (ModFeaturePost, Option<PersonSafe>, Post, CommunitySafe);
|
||||
|
||||
impl ModStickyPostView {
|
||||
impl ModFeaturePostView {
|
||||
pub async fn list(pool: &DbPool, params: ModlogListParams) -> Result<Vec<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let person_alias_1 = diesel::alias!(person as person1);
|
||||
|
@ -32,16 +32,16 @@ impl ModStickyPostView {
|
|||
let show_mod_names = !params.hide_modlog_names;
|
||||
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
|
||||
|
||||
let admin_names_join = mod_sticky_post::mod_person_id
|
||||
let admin_names_join = mod_feature_post::mod_person_id
|
||||
.eq(person::id)
|
||||
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
|
||||
let mut query = mod_sticky_post::table
|
||||
let mut query = mod_feature_post::table
|
||||
.left_join(person::table.on(admin_names_join))
|
||||
.inner_join(post::table)
|
||||
.inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
|
||||
.inner_join(community::table.on(post::community_id.eq(community::id)))
|
||||
.select((
|
||||
mod_sticky_post::all_columns,
|
||||
mod_feature_post::all_columns,
|
||||
Person::safe_columns_tuple().nullable(),
|
||||
post::all_columns,
|
||||
Community::safe_columns_tuple(),
|
||||
|
@ -53,7 +53,7 @@ impl ModStickyPostView {
|
|||
};
|
||||
|
||||
if let Some(mod_person_id) = params.mod_person_id {
|
||||
query = query.filter(mod_sticky_post::mod_person_id.eq(mod_person_id));
|
||||
query = query.filter(mod_feature_post::mod_person_id.eq(mod_person_id));
|
||||
};
|
||||
|
||||
if let Some(other_person_id) = params.other_person_id {
|
||||
|
@ -65,8 +65,8 @@ impl ModStickyPostView {
|
|||
let res = query
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.order_by(mod_sticky_post::when_.desc())
|
||||
.load::<ModStickyPostViewTuple>(conn)
|
||||
.order_by(mod_feature_post::when_.desc())
|
||||
.load::<ModFeaturePostViewTuple>(conn)
|
||||
.await?;
|
||||
|
||||
let results = Self::from_tuple_to_vec(res);
|
||||
|
@ -74,13 +74,13 @@ impl ModStickyPostView {
|
|||
}
|
||||
}
|
||||
|
||||
impl ViewToVec for ModStickyPostView {
|
||||
type DbTuple = ModStickyPostViewTuple;
|
||||
impl ViewToVec for ModFeaturePostView {
|
||||
type DbTuple = ModFeaturePostViewTuple;
|
||||
fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
|
||||
items
|
||||
.into_iter()
|
||||
.map(|a| Self {
|
||||
mod_sticky_post: a.0,
|
||||
mod_feature_post: a.0,
|
||||
moderator: a.1,
|
||||
post: a.2,
|
||||
community: a.3,
|
|
@ -12,12 +12,12 @@ use lemmy_db_schema::{
|
|||
ModAddCommunity,
|
||||
ModBan,
|
||||
ModBanFromCommunity,
|
||||
ModFeaturePost,
|
||||
ModHideCommunity,
|
||||
ModLockPost,
|
||||
ModRemoveComment,
|
||||
ModRemoveCommunity,
|
||||
ModRemovePost,
|
||||
ModStickyPost,
|
||||
ModTransferCommunity,
|
||||
},
|
||||
person::PersonSafe,
|
||||
|
@ -97,8 +97,8 @@ pub struct ModRemovePostView {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ModStickyPostView {
|
||||
pub mod_sticky_post: ModStickyPost,
|
||||
pub struct ModFeaturePostView {
|
||||
pub mod_feature_post: ModFeaturePost,
|
||||
pub moderator: Option<PersonSafe>,
|
||||
pub post: Post,
|
||||
pub community: CommunitySafe,
|
||||
|
|
47
migrations/2022-11-20-032430_sticky_local/down.sql
Normal file
47
migrations/2022-11-20-032430_sticky_local/down.sql
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
DROP TRIGGER IF EXISTS post_aggregates_featured_local ON post;
|
||||
DROP TRIGGER IF EXISTS post_aggregates_featured_community ON post;
|
||||
drop function post_aggregates_featured_community;
|
||||
drop function post_aggregates_featured_local;
|
||||
|
||||
|
||||
alter table post ADD stickied boolean NOT NULL DEFAULT false;
|
||||
Update post
|
||||
set stickied = featured_community;
|
||||
alter table post DROP COLUMN featured_community;
|
||||
alter table post DROP COLUMN featured_local;
|
||||
|
||||
alter table post_aggregates ADD stickied boolean NOT NULL DEFAULT false;
|
||||
Update post_aggregates
|
||||
set stickied = featured_community;
|
||||
alter table post_aggregates DROP COLUMN featured_community;
|
||||
alter table post_aggregates DROP COLUMN featured_local;
|
||||
|
||||
alter table mod_feature_post
|
||||
rename column featured TO stickied;
|
||||
|
||||
alter table mod_feature_post
|
||||
DROP COLUMN is_featured_community;
|
||||
|
||||
alter table mod_feature_post
|
||||
alter column stickied DROP NOT NULL;
|
||||
|
||||
alter table mod_feature_post
|
||||
Rename To mod_sticky_post;
|
||||
|
||||
create function post_aggregates_stickied()
|
||||
returns trigger language plpgsql
|
||||
as $$
|
||||
begin
|
||||
update post_aggregates pa
|
||||
set stickied = NEW.stickied
|
||||
where pa.post_id = NEW.id;
|
||||
|
||||
return null;
|
||||
end $$;
|
||||
|
||||
create trigger post_aggregates_stickied
|
||||
after update on post
|
||||
for each row
|
||||
when (OLD.stickied is distinct from NEW.stickied)
|
||||
execute procedure post_aggregates_stickied();
|
63
migrations/2022-11-20-032430_sticky_local/up.sql
Normal file
63
migrations/2022-11-20-032430_sticky_local/up.sql
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
DROP TRIGGER IF EXISTS post_aggregates_stickied ON post;
|
||||
drop function
|
||||
post_aggregates_stickied;
|
||||
|
||||
|
||||
alter table post ADD featured_community boolean NOT NULL DEFAULT false;
|
||||
alter table post ADD featured_local boolean NOT NULL DEFAULT false;
|
||||
update post
|
||||
set featured_community = stickied;
|
||||
alter table post DROP COLUMN stickied;
|
||||
|
||||
alter table post_aggregates ADD featured_community boolean NOT NULL DEFAULT false;
|
||||
alter table post_aggregates ADD featured_local boolean NOT NULL DEFAULT false;
|
||||
update post_aggregates
|
||||
set featured_community = stickied;
|
||||
alter table post_aggregates DROP COLUMN stickied;
|
||||
|
||||
alter table mod_sticky_post
|
||||
rename column stickied TO featured;
|
||||
|
||||
alter table mod_sticky_post
|
||||
alter column featured SET NOT NULL;
|
||||
|
||||
alter table mod_sticky_post
|
||||
ADD is_featured_community boolean NOT NULL DEFAULT true;
|
||||
|
||||
alter table mod_sticky_post
|
||||
Rename To mod_feature_post;
|
||||
|
||||
create function post_aggregates_featured_community()
|
||||
returns trigger language plpgsql
|
||||
as $$
|
||||
begin
|
||||
update post_aggregates pa
|
||||
set featured_community = NEW.featured_community
|
||||
where pa.post_id = NEW.id;
|
||||
return null;
|
||||
end $$;
|
||||
|
||||
create function post_aggregates_featured_local()
|
||||
returns trigger language plpgsql
|
||||
as $$
|
||||
begin
|
||||
update post_aggregates pa
|
||||
set featured_local = NEW.featured_local
|
||||
where pa.post_id = NEW.id;
|
||||
return null;
|
||||
end $$;
|
||||
|
||||
CREATE TRIGGER post_aggregates_featured_community
|
||||
AFTER UPDATE
|
||||
ON public.post
|
||||
FOR EACH ROW
|
||||
WHEN (old.featured_community IS DISTINCT FROM new.featured_community)
|
||||
EXECUTE FUNCTION public.post_aggregates_featured_community();
|
||||
|
||||
CREATE TRIGGER post_aggregates_featured_local
|
||||
AFTER UPDATE
|
||||
ON public.post
|
||||
FOR EACH ROW
|
||||
WHEN (old.featured_local IS DISTINCT FROM new.featured_local)
|
||||
EXECUTE FUNCTION public.post_aggregates_featured_local();
|
|
@ -59,6 +59,7 @@ use lemmy_api_common::{
|
|||
CreatePostReport,
|
||||
DeletePost,
|
||||
EditPost,
|
||||
FeaturePost,
|
||||
GetPost,
|
||||
GetPosts,
|
||||
GetSiteMetadata,
|
||||
|
@ -68,7 +69,6 @@ use lemmy_api_common::{
|
|||
RemovePost,
|
||||
ResolvePostReport,
|
||||
SavePost,
|
||||
StickyPost,
|
||||
},
|
||||
private_message::{
|
||||
CreatePrivateMessage,
|
||||
|
@ -183,7 +183,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
web::post().to(route_post::<MarkPostAsRead>),
|
||||
)
|
||||
.route("/lock", web::post().to(route_post::<LockPost>))
|
||||
.route("/sticky", web::post().to(route_post::<StickyPost>))
|
||||
.route("/feature", web::post().to(route_post::<FeaturePost>))
|
||||
.route("/list", web::get().to(route_get_apub::<GetPosts>))
|
||||
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
||||
.route("/save", web::put().to(route_post::<SavePost>))
|
||||
|
|
|
@ -60,6 +60,7 @@ use lemmy_api_common::{
|
|||
CreatePostReport,
|
||||
DeletePost,
|
||||
EditPost,
|
||||
FeaturePost,
|
||||
GetPost,
|
||||
GetPosts,
|
||||
GetSiteMetadata,
|
||||
|
@ -69,7 +70,6 @@ use lemmy_api_common::{
|
|||
RemovePost,
|
||||
ResolvePostReport,
|
||||
SavePost,
|
||||
StickyPost,
|
||||
},
|
||||
private_message::{
|
||||
CreatePrivateMessage,
|
||||
|
@ -560,7 +560,9 @@ pub async fn match_websocket_operation(
|
|||
|
||||
// Post ops
|
||||
UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
|
||||
UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
|
||||
UserOperation::FeaturePost => {
|
||||
do_websocket_operation::<FeaturePost>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::CreatePostLike => {
|
||||
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue