refactor(post): refresh post crate (features, handlers, service) and add post views to export
zhenyi committed
Modified lib/post/features/post/usecase/archive.rs lib/post/features/post/usecase/archive.rs +14 −2 View lib/post/features/post/usecase/archive.rs
@@ -1,11 +1,12 @@
11use db::conn::sea_orm::*;
22use db::post::post::PostStatus;
3use export::user::basic::UserBasicInfo;
34use time::OffsetDateTime;
45use uuid::Uuid;
56
67use crate::error::PostResult;
8use crate::features::PostService;
79use crate::features::authz;
8use crate::features::PostService;
910use crate::metrics;
1011
1112use super::super::PostView;
@@ -30,7 +31,18 @@
3031 active.closed_at = Set(None);
3132 active.updated_at = Set(Some(now));
3233 let saved = active.update(&db).await?;
33 Ok(PostView::from(saved))
34 let author_id = saved.author_id;
35 let last_reply_by = saved.last_reply_by;
36 let users = db::user::users_loader::load_users(&svc.db, &[author_id]).await?;
37 let last_reply_users = match last_reply_by {
38 Some(id) => db::user::users_loader::load_users(&svc.db, &[id]).await?,
39 None => Default::default(),
40 };
41 Ok(PostView::from_model(
42 saved,
43 users.get(&author_id).map(UserBasicInfo::from),
44 last_reply_by.and_then(|id| last_reply_users.get(&id).map(UserBasicInfo::from)),
45 ))
3446 }
3547 .await;
3648 metrics::record_outcome(metrics::FEATURE_POSTS_ARCHIVE, &result);
Modified lib/post/features/post/usecase/close.rs lib/post/features/post/usecase/close.rs +14 −2 View lib/post/features/post/usecase/close.rs
@@ -1,11 +1,12 @@
11use db::conn::sea_orm::*;
22use db::post::post::PostStatus;
3use export::user::basic::UserBasicInfo;
34use time::OffsetDateTime;
45use uuid::Uuid;
56
67use crate::error::PostResult;
8use crate::features::PostService;
79use crate::features::authz;
8use crate::features::PostService;
910use crate::metrics;
1011
1112use super::super::PostView;
@@ -30,7 +31,18 @@
3031 active.archived_at = Set(None);
3132 active.updated_at = Set(Some(now));
3233 let saved = active.update(&db).await?;
33 Ok(PostView::from(saved))
34 let author_id = saved.author_id;
35 let last_reply_by = saved.last_reply_by;
36 let users = db::user::users_loader::load_users(&svc.db, &[author_id]).await?;
37 let last_reply_users = match last_reply_by {
38 Some(id) => db::user::users_loader::load_users(&svc.db, &[id]).await?,
39 None => Default::default(),
40 };
41 Ok(PostView::from_model(
42 saved,
43 users.get(&author_id).map(UserBasicInfo::from),
44 last_reply_by.and_then(|id| last_reply_users.get(&id).map(UserBasicInfo::from)),
45 ))
3446 }
3547 .await;
3648 metrics::record_outcome(metrics::FEATURE_POSTS_CLOSE, &result);
Modified lib/post/features/post/usecase/create.rs lib/post/features/post/usecase/create.rs +10 −11 View lib/post/features/post/usecase/create.rs
@@ -1,17 +1,18 @@
11use db::conn::sea_orm::*;
22use db::post::post as post_entity;
3use export::user::basic::UserBasicInfo;
34use space::features::channels::usecase::ensure_channel_for_resource;
45use time::OffsetDateTime;
56use uuid::Uuid;
67
8use super::super::{CreatePostOption, PostView};
9use super::helpers::require_authenticated;
710use crate::error::{PostError, PostResult};
811use crate::features::PostService;
912use crate::features::posts::usecase::helpers::{
1013 DEFAULT_BOARD_NAME, ensure_default_collection, find_board_by_space,
1114};
1215use crate::metrics;
13use super::super::{CreatePostOption, PostView};
14use super::helpers::require_authenticated;
1516
1617pub const MAX_TITLE_LEN: usize = 200;
1718pub const MAX_BODY_LEN: usize = 1_000_000;
@@ -44,14 +45,9 @@
4445 let channel_id = match find_board_by_space(&txn, space_id).await? {
4546 Some(board) => board.channel_id,
4647 None => {
47 let channel = ensure_channel_for_resource(
48 &txn,
49 space_id,
50 None,
51 DEFAULT_BOARD_NAME,
52 actor,
53 )
54 .await?;
48 let channel =
49 ensure_channel_for_resource(&txn, space_id, None, DEFAULT_BOARD_NAME, actor)
50 .await?;
5551 ensure_default_collection(&txn, channel.id, actor).await?;
5652 channel.id
5753 }
@@ -91,7 +87,10 @@
9187 let saved = active.insert(&txn).await?;
9288
9389 txn.commit().await?;
94 Ok(PostView::from(saved))
90 let author = db::user::users_loader::load_user(&svc.db, actor)
91 .await?
92 .map(UserBasicInfo::from);
93 Ok(PostView::from_model(saved, author, None))
9594 }
9695 .await;
9796 metrics::record_outcome(metrics::FEATURE_POSTS_CREATE, &result);
Modified lib/post/features/post/usecase/delete.rs lib/post/features/post/usecase/delete.rs +1 −1 View lib/post/features/post/usecase/delete.rs
@@ -2,8 +2,8 @@
22use uuid::Uuid;
33
44use crate::error::PostResult;
5use crate::features::PostService;
56use crate::features::authz;
6use crate::features::PostService;
77use crate::metrics;
88
99use super::helpers::{load_post, require_authenticated};
Modified lib/post/features/post/usecase/get.rs lib/post/features/post/usecase/get.rs +13 −1 View lib/post/features/post/usecase/get.rs
@@ -1,3 +1,4 @@
1use export::user::basic::UserBasicInfo;
12use uuid::Uuid;
23
34use crate::error::PostResult;
@@ -14,5 +15,16 @@
1415) -> PostResult<PostView> {
1516 require_authenticated(actor)?;
1617 let cur = load_post(svc, channel_id, post_id).await?;
17 Ok(PostView::from(cur))
18 let author_id = cur.author_id;
19 let last_reply_by = cur.last_reply_by;
20 let users = db::user::users_loader::load_users(&svc.db, &[author_id]).await?;
21 let last_reply_users = match last_reply_by {
22 Some(id) => db::user::users_loader::load_users(&svc.db, &[id]).await?,
23 None => Default::default(),
24 };
25 Ok(PostView::from_model(
26 cur,
27 users.get(&author_id).map(UserBasicInfo::from),
28 last_reply_by.and_then(|id| last_reply_users.get(&id).map(UserBasicInfo::from)),
29 ))
1830}
Modified lib/post/features/post/usecase/reopen.rs lib/post/features/post/usecase/reopen.rs +14 −2 View lib/post/features/post/usecase/reopen.rs
@@ -1,11 +1,12 @@
11use db::conn::sea_orm::*;
22use db::post::post::PostStatus;
3use export::user::basic::UserBasicInfo;
34use time::OffsetDateTime;
45use uuid::Uuid;
56
67use crate::error::PostResult;
8use crate::features::PostService;
79use crate::features::authz;
8use crate::features::PostService;
910use crate::metrics;
1011
1112use super::super::PostView;
@@ -30,7 +31,18 @@
3031 active.archived_at = Set(None);
3132 active.updated_at = Set(Some(now));
3233 let saved = active.update(&db).await?;
33 Ok(PostView::from(saved))
34 let author_id = saved.author_id;
35 let last_reply_by = saved.last_reply_by;
36 let users = db::user::users_loader::load_users(&svc.db, &[author_id]).await?;
37 let last_reply_users = match last_reply_by {
38 Some(id) => db::user::users_loader::load_users(&svc.db, &[id]).await?,
39 None => Default::default(),
40 };
41 Ok(PostView::from_model(
42 saved,
43 users.get(&author_id).map(UserBasicInfo::from),
44 last_reply_by.and_then(|id| last_reply_users.get(&id).map(UserBasicInfo::from)),
45 ))
3446 }
3547 .await;
3648 metrics::record_outcome(metrics::FEATURE_POSTS_REOPEN, &result);
Modified lib/post/features/post/usecase/update.rs lib/post/features/post/usecase/update.rs +15 −3 View lib/post/features/post/usecase/update.rs
@@ -1,15 +1,16 @@
11use db::conn::sea_orm::*;
2use export::user::basic::UserBasicInfo;
23use time::OffsetDateTime;
34use uuid::Uuid;
45
56use crate::error::{PostError, PostResult};
6use crate::features::authz;
77use crate::features::PostService;
8use crate::features::authz;
89use crate::metrics;
910
11use super::super::{PostStatusView, PostView, UpdatePostOption};
1012use super::create::{MAX_BODY_LEN, MAX_TITLE_LEN};
1113use super::helpers::{load_post, require_authenticated};
12use super::super::{PostStatusView, PostView, UpdatePostOption};
1314
1415pub async fn update_post(
1516 svc: &PostService,
@@ -55,7 +56,18 @@
5556 active.updated_at = Set(Some(now));
5657
5758 let saved = active.update(&db).await?;
58 Ok(PostView::from(saved))
59 let author_id = saved.author_id;
60 let last_reply_by = saved.last_reply_by;
61 let users = db::user::users_loader::load_users(&svc.db, &[author_id]).await?;
62 let last_reply_users = match last_reply_by {
63 Some(id) => db::user::users_loader::load_users(&svc.db, &[id]).await?,
64 None => Default::default(),
65 };
66 Ok(PostView::from_model(
67 saved,
68 users.get(&author_id).map(UserBasicInfo::from),
69 last_reply_by.and_then(|id| last_reply_users.get(&id).map(UserBasicInfo::from)),
70 ))
5971 }
6072 .await;
6173 metrics::record_outcome(metrics::FEATURE_POSTS_UPDATE, &result);
Modified lib/post/features/post_label/usecase/bind.rs lib/post/features/post_label/usecase/bind.rs +1 −1 View lib/post/features/post_label/usecase/bind.rs
@@ -7,8 +7,8 @@
77use crate::features::PostService;
88use crate::metrics;
99
10use super::helpers::{load_post_label, require_authenticated};
1011use crate::features::post::usecase::load_post;
11use super::helpers::{load_post_label, require_authenticated};
1212
1313pub async fn bind_post_label(
1414 svc: &PostService,
Modified lib/post/features/post_label/usecase/list_for_post.rs lib/post/features/post_label/usecase/list_for_post.rs +1 −1 View lib/post/features/post_label/usecase/list_for_post.rs
@@ -7,9 +7,9 @@
77use crate::features::PostService;
88use crate::metrics;
99
10use crate::features::post::usecase::load_post;
1110use super::super::PostLabelView;
1211use super::helpers::require_authenticated;
12use crate::features::post::usecase::load_post;
1313
1414pub async fn list_post_labels_for_post(
1515 svc: &PostService,
Modified lib/post/features/post_label/usecase/unbind.rs lib/post/features/post_label/usecase/unbind.rs +1 −1 View lib/post/features/post_label/usecase/unbind.rs
@@ -6,8 +6,8 @@
66use crate::features::PostService;
77use crate::metrics;
88
9use super::helpers::{load_post_label, require_authenticated};
910use crate::features::post::usecase::load_post;
10use super::helpers::{load_post_label, require_authenticated};
1111
1212pub async fn unbind_post_label(
1313 svc: &PostService,
Modified lib/post/features/post_label/impls.rs lib/post/features/post_label/impls.rs +1 −3 View lib/post/features/post_label/impls.rs
@@ -4,9 +4,7 @@
44use crate::features::PostService;
55
66use super::usecase;
7use super::{
8 CreatePostLabelOption, PostLabelPage, PostLabelView, UpdatePostLabelOption,
9};
7use super::{CreatePostLabelOption, PostLabelPage, PostLabelView, UpdatePostLabelOption};
108
119impl PostService {
1210 pub async fn create_post_label(
Modified lib/post/features/post_mention/usecase/create.rs lib/post/features/post_mention/usecase/create.rs +14 −6 View lib/post/features/post_mention/usecase/create.rs
@@ -1,6 +1,7 @@
11use db::conn::sea_orm::*;
22use db::post::post_mentions as mention_entity;
33use db::post::post_mentions::MentionTarget;
4use export::user::basic::UserBasicInfo;
45use time::OffsetDateTime;
56use uuid::Uuid;
67
@@ -8,8 +9,8 @@
89use crate::features::PostService;
910use crate::metrics;
1011
11use crate::features::post::usecase::load_post;
1212use super::super::{CreateMentionOption, PostMentionView};
13use crate::features::post::usecase::load_post;
1314
1415pub async fn create_post_mention(
1516 svc: &PostService,
@@ -21,11 +22,12 @@
2122 let _timer = metrics::Timer::start(metrics::FEATURE_POST_MENTIONS_CREATE);
2223 let result: PostResult<PostMentionView> = async {
2324 if actor.is_nil() {
24 return Err(PostError::Unauthorized(
25 "authentication required".into(),
26 ));
25 return Err(PostError::Unauthorized("authentication required".into()));
2726 }
28 if input.user_id.is_none() && input.role_id.is_none() && !input.is_everyone && !input.is_here
27 if input.user_id.is_none()
28 && input.role_id.is_none()
29 && !input.is_everyone
30 && !input.is_here
2931 {
3032 return Err(PostError::BadRequest(
3133 "mention requires a user, role, @everyone or @here target".into(),
@@ -48,7 +50,13 @@
4850 .set_created_at(OffsetDateTime::now_utc())
4951 .into();
5052 let saved = active.insert(&db).await?;
51 Ok(PostMentionView::from(saved))
53 let user = match saved.user_id {
54 Some(id) => db::user::users_loader::load_user(&svc.db, id)
55 .await?
56 .map(UserBasicInfo::from),
57 None => None,
58 };
59 Ok(PostMentionView::from_model(saved, user))
5260 }
5361 .await;
5462 metrics::record_outcome(metrics::FEATURE_POST_MENTIONS_CREATE, &result);
Modified lib/post/features/post_mention/usecase/list.rs lib/post/features/post_mention/usecase/list.rs +15 −5 View lib/post/features/post_mention/usecase/list.rs
@@ -1,14 +1,15 @@
11use db::conn::sea_orm::*;
22use db::post::post_mentions as mention_entity;
33use db::post::post_mentions::MentionTarget;
4use export::user::basic::UserBasicInfo;
45use uuid::Uuid;
56
67use crate::error::{PostError, PostResult};
78use crate::features::PostService;
89use crate::metrics;
910
10use crate::features::post::usecase::load_post;
1111use super::super::PostMentionView;
12use crate::features::post::usecase::load_post;
1213
1314const MAX_PAGINATION: u64 = 100;
1415const DEFAULT_PAGINATION: u64 = 50;
@@ -24,9 +25,7 @@
2425 let _timer = metrics::Timer::start(metrics::FEATURE_POST_MENTIONS_LIST);
2526 let result: PostResult<Vec<PostMentionView>> = async {
2627 if actor.is_nil() {
27 return Err(PostError::Unauthorized(
28 "authentication required".into(),
29 ));
28 return Err(PostError::Unauthorized("authentication required".into()));
3029 }
3130 let limit = limit.unwrap_or(DEFAULT_PAGINATION);
3231 let offset = offset.unwrap_or(0);
@@ -47,7 +46,18 @@
4746 .offset(offset)
4847 .all(&db)
4948 .await?;
50 Ok(rows.into_iter().map(PostMentionView::from).collect())
49 let user_ids: Vec<Uuid> = rows.iter().filter_map(|r| r.user_id).collect();
50 let users = db::user::users_loader::load_users(&svc.db, &user_ids).await?;
51 Ok(rows
52 .into_iter()
53 .map(|r| {
54 let user_id = r.user_id;
55 PostMentionView::from_model(
56 r,
57 user_id.and_then(|id| users.get(&id).map(UserBasicInfo::from)),
58 )
59 })
60 .collect())
5161 }
5262 .await;
5363 metrics::record_outcome(metrics::FEATURE_POST_MENTIONS_LIST, &result);
Modified lib/post/features/post_reaction/usecase/create.rs lib/post/features/post_reaction/usecase/create.rs +6 −2 View lib/post/features/post_reaction/usecase/create.rs
@@ -1,6 +1,7 @@
11use db::conn::sea_orm::*;
22use db::post::post_reactions as reaction_entity;
33use db::post::post_reactions::ReactionTarget;
4use export::user::basic::UserBasicInfo;
45use time::OffsetDateTime;
56use uuid::Uuid;
67
@@ -8,8 +9,8 @@
89use crate::features::PostService;
910use crate::metrics;
1011
12use super::super::{CreatePostReactionOption, PostReactionView};
1113use crate::features::post::usecase::load_post;
12use super::super::{CreatePostReactionOption, PostReactionView};
1314
1415pub const MAX_EMOJI_LEN: usize = 32;
1516
@@ -63,7 +64,10 @@
6364 .set_created_at(OffsetDateTime::now_utc())
6465 .into();
6566 let saved = active.insert(&db).await?;
66 Ok(PostReactionView::from(saved))
67 let user = db::user::users_loader::load_user(&svc.db, actor)
68 .await?
69 .map(UserBasicInfo::from);
70 Ok(PostReactionView::from_model(saved, user))
6771 }
6872 .await;
6973 metrics::record_outcome(metrics::FEATURE_POST_REACTIONS_CREATE, &result);
Modified lib/post/features/post_reaction/usecase/delete.rs lib/post/features/post_reaction/usecase/delete.rs +1 −3 View lib/post/features/post_reaction/usecase/delete.rs
@@ -18,9 +18,7 @@
1818 let _timer = metrics::Timer::start(metrics::FEATURE_POST_REACTIONS_DELETE);
1919 let result: PostResult<()> = async {
2020 if actor.is_nil() {
21 return Err(PostError::Unauthorized(
22 "authentication required".into(),
23 ));
21 return Err(PostError::Unauthorized("authentication required".into()));
2422 }
2523 load_post(svc, channel_id, post_id).await?;
2624
Modified lib/post/features/post_reaction/usecase/list.rs lib/post/features/post_reaction/usecase/list.rs +12 −5 View lib/post/features/post_reaction/usecase/list.rs
@@ -1,14 +1,15 @@
11use db::conn::sea_orm::*;
22use db::post::post_reactions as reaction_entity;
33use db::post::post_reactions::ReactionTarget;
4use export::user::basic::UserBasicInfo;
45use uuid::Uuid;
56
67use crate::error::{PostError, PostResult};
78use crate::features::PostService;
89use crate::metrics;
910
10use crate::features::post::usecase::load_post;
1111use super::super::PostReactionView;
12use crate::features::post::usecase::load_post;
1213
1314const MAX_PAGINATION: u64 = 100;
1415const DEFAULT_PAGINATION: u64 = 50;
@@ -24,9 +25,7 @@
2425 let _timer = metrics::Timer::start(metrics::FEATURE_POST_REACTIONS_LIST);
2526 let result: PostResult<Vec<PostReactionView>> = async {
2627 if actor.is_nil() {
27 return Err(PostError::Unauthorized(
28 "authentication required".into(),
29 ));
28 return Err(PostError::Unauthorized("authentication required".into()));
3029 }
3130 let limit = limit.unwrap_or(DEFAULT_PAGINATION);
3231 let offset = offset.unwrap_or(0);
@@ -47,7 +46,15 @@
4746 .offset(offset)
4847 .all(&db)
4948 .await?;
50 Ok(rows.into_iter().map(PostReactionView::from).collect())
49 let user_ids: Vec<Uuid> = rows.iter().map(|r| r.user_id).collect();
50 let users = db::user::users_loader::load_users(&svc.db, &user_ids).await?;
51 Ok(rows
52 .into_iter()
53 .map(|r| {
54 let user_id = r.user_id;
55 PostReactionView::from_model(r, users.get(&user_id).map(UserBasicInfo::from))
56 })
57 .collect())
5158 }
5259 .await;
5360 metrics::record_outcome(metrics::FEATURE_POST_REACTIONS_LIST, &result);
Modified lib/post/features/post_reply/usecase/create.rs lib/post/features/post_reply/usecase/create.rs +7 −2 View lib/post/features/post_reply/usecase/create.rs
@@ -1,12 +1,14 @@
11use db::conn::sea_orm::*;
2use export::user::basic::UserBasicInfo;
23use time::OffsetDateTime;
34use uuid::Uuid;
45
56use crate::error::{PostError, PostResult};
67use crate::features::PostService;
78
8use crate::features::post::usecase::load_post;
9use super::super::PostReplyView;
910use super::helpers::require_authenticated;
11use crate::features::post::usecase::load_post;
1012
1113/// Ensure a reply's parent reply (when given) belongs to the same post.
1214pub async fn ensure_parent_reply(
@@ -79,7 +81,10 @@
7981 post_active.update(&txn).await?;
8082
8183 txn.commit().await?;
82 Ok(saved.into())
84 let author = db::user::users_loader::load_user(&svc.db, actor)
85 .await?
86 .map(UserBasicInfo::from);
87 Ok(PostReplyView::from_model(saved, author, None))
8388 }
8489 .await;
8590 crate::metrics::record_outcome(crate::metrics::FEATURE_REPLIES_CREATE, &result);
Modified lib/post/features/post_reply/usecase/list.rs lib/post/features/post_reply/usecase/list.rs +22 −2 View lib/post/features/post_reply/usecase/list.rs
@@ -1,14 +1,15 @@
11use db::conn::sea_orm::*;
22use db::post::post_replies as reply_entity;
3use export::user::basic::UserBasicInfo;
34use uuid::Uuid;
45
56use crate::error::{PostError, PostResult};
67use crate::features::PostService;
78use crate::metrics;
89
9use crate::features::post::usecase::load_post;
1010use super::super::{PostReplyPage, PostReplyView};
1111use super::helpers::require_authenticated;
12use crate::features::post::usecase::load_post;
1213
1314const MAX_PAGINATION: u64 = 100;
1415const DEFAULT_PAGINATION: u64 = 20;
@@ -48,7 +49,26 @@
4849 .all(&db)
4950 .await?;
5051
51 let items = rows.into_iter().map(PostReplyView::from).collect();
52 let mut user_ids: Vec<Uuid> = Vec::new();
53 for r in &rows {
54 user_ids.push(r.author_id);
55 if let Some(id) = r.deleted_by {
56 user_ids.push(id);
57 }
58 }
59 let users = db::user::users_loader::load_users(&svc.db, &user_ids).await?;
60 let items = rows
61 .into_iter()
62 .map(|r| {
63 let author_id = r.author_id;
64 let deleted_by = r.deleted_by;
65 PostReplyView::from_model(
66 r,
67 users.get(&author_id).map(UserBasicInfo::from),
68 deleted_by.and_then(|id| users.get(&id).map(UserBasicInfo::from)),
69 )
70 })
71 .collect();
5272 Ok(PostReplyPage { items, total })
5373 }
5474 .await;
Modified lib/post/features/post_watch/usecase/helpers.rs lib/post/features/post_watch/usecase/helpers.rs +10 −3 View lib/post/features/post_watch/usecase/helpers.rs
@@ -1,6 +1,7 @@
11use db::common::watch_mode::WatchMode;
22use db::conn::sea_orm::*;
33use db::post::post_watch as watch_entity;
4use export::user::basic::UserBasicInfo;
45use time::OffsetDateTime;
56use uuid::Uuid;
67
@@ -8,8 +9,8 @@
89use crate::features::PostService;
910use crate::metrics;
1011
12use super::super::PostWatchView;
1113use crate::features::post::usecase::load_post;
12use super::super::PostWatchView;
1314
1415pub fn require_authenticated(actor: Uuid) -> PostResult<()> {
1516 if actor.is_nil() {
@@ -86,7 +87,10 @@
8687 .into();
8788 active.insert(&db).await?
8889 };
89 Ok(PostWatchView::from(saved))
90 let user = db::user::users_loader::load_user(&svc.db, actor)
91 .await?
92 .map(UserBasicInfo::from);
93 Ok(PostWatchView::from_model(saved, user))
9094 }
9195 .await;
9296 metrics::record_outcome(metrics::FEATURE_POST_WATCHES_UPSERT, &result);
@@ -104,7 +108,10 @@
104108 require_authenticated(actor)?;
105109 load_post(svc, channel_id, post_id).await?;
106110 let cur = load_my_watch(svc, post_id, actor).await?;
107 Ok(PostWatchView::from(cur))
111 let user = db::user::users_loader::load_user(&svc.db, actor)
112 .await?
113 .map(UserBasicInfo::from);
114 Ok(PostWatchView::from_model(cur, user))
108115 }
109116 .await;
110117 metrics::record_outcome(metrics::FEATURE_POST_WATCHES_GET, &result);
Modified lib/post/features/posts/usecase/create.rs lib/post/features/posts/usecase/create.rs +12 −18 View lib/post/features/posts/usecase/create.rs
@@ -55,24 +55,18 @@
5555 .writer()
5656 .transaction(|txn| {
5757 Box::pin(async move {
58 let object_channel = ensure_channel_for_resource(
59 txn,
60 space_id,
61 input.parent_dir,
62 &name,
63 actor,
64 )
65 .await?;
66 let active: posts_entity::ActiveModel =
67 posts_entity::ActiveModel::builder()
68 .set_id(collection_id)
69 .set_channel_id(object_channel.id)
70 .set_name(name)
71 .set_icon(input.icon)
72 .set_description(input.description)
73 .set_created_at(now)
74 .set_updated_at(None)
75 .into();
58 let object_channel =
59 ensure_channel_for_resource(txn, space_id, input.parent_dir, &name, actor)
60 .await?;
61 let active: posts_entity::ActiveModel = posts_entity::ActiveModel::builder()
62 .set_id(collection_id)
63 .set_channel_id(object_channel.id)
64 .set_name(name)
65 .set_icon(input.icon)
66 .set_description(input.description)
67 .set_created_at(now)
68 .set_updated_at(None)
69 .into();
7670 Ok(posts_entity::Entity::insert(active)
7771 .exec_with_returning(txn)
7872 .await?)
Modified lib/post/features/posts/usecase/list.rs lib/post/features/posts/usecase/list.rs +33 −13 View lib/post/features/posts/usecase/list.rs
@@ -1,6 +1,7 @@
11use db::conn::sea_orm::*;
22use db::post::post as post_entity;
33use db::post::posts as posts_entity;
4use export::user::basic::UserBasicInfo;
45use uuid::Uuid;
56
67use crate::error::{PostError, PostResult};
@@ -63,18 +64,18 @@
6364 let finder = post_entity::Entity::find()
6465 .filter(post_entity::Column::CollectionId.eq(collection.id))
6566 .apply_if(q.status, |f, s| match s {
66 PostStatusView::Open => f.filter(post_entity::Column::Status.eq(
67 post_entity::PostStatus::Open,
68 )),
69 PostStatusView::Closed => f.filter(post_entity::Column::Status.eq(
70 post_entity::PostStatus::Closed,
71 )),
72 PostStatusView::Archived => f.filter(post_entity::Column::Status.eq(
73 post_entity::PostStatus::Archived,
74 )),
75 PostStatusView::Locked => f.filter(post_entity::Column::Status.eq(
76 post_entity::PostStatus::Locked,
77 )),
67 PostStatusView::Open => {
68 f.filter(post_entity::Column::Status.eq(post_entity::PostStatus::Open))
69 }
70 PostStatusView::Closed => {
71 f.filter(post_entity::Column::Status.eq(post_entity::PostStatus::Closed))
72 }
73 PostStatusView::Archived => {
74 f.filter(post_entity::Column::Status.eq(post_entity::PostStatus::Archived))
75 }
76 PostStatusView::Locked => {
77 f.filter(post_entity::Column::Status.eq(post_entity::PostStatus::Locked))
78 }
7879 })
7980 .apply_if(q.author_id, |f, uid| {
8081 f.filter(post_entity::Column::AuthorId.eq(uid))
@@ -91,7 +92,26 @@
9192 .all(&db)
9293 .await?;
9394
94 let items = rows.into_iter().map(PostView::from).collect();
95 let mut user_ids: Vec<Uuid> = Vec::new();
96 for r in &rows {
97 user_ids.push(r.author_id);
98 if let Some(id) = r.last_reply_by {
99 user_ids.push(id);
100 }
101 }
102 let users = db::user::users_loader::load_users(&svc.db, &user_ids).await?;
103 let items = rows
104 .into_iter()
105 .map(|r| {
106 let author_id = r.author_id;
107 let last_reply_by = r.last_reply_by;
108 PostView::from_model(
109 r,
110 users.get(&author_id).map(UserBasicInfo::from),
111 last_reply_by.and_then(|id| users.get(&id).map(UserBasicInfo::from)),
112 )
113 })
114 .collect();
95115 Ok(PostPage { items, total })
96116 }
97117 .await;
Modified lib/post/features/authz.rs lib/post/features/authz.rs +1 −5 View lib/post/features/authz.rs
@@ -41,11 +41,7 @@
4141
4242/// - Site admins: always allowed.
4343/// - Channel owner (top-level / space-less channel): allowed.
44pub async fn authorize_post(
45 svc: &PostService,
46 actor: Uuid,
47 channel_id: Uuid,
48) -> PostResult<()> {
44pub async fn authorize_post(svc: &PostService, actor: Uuid, channel_id: Uuid) -> PostResult<()> {
4945 if actor.is_nil() {
5046 return Err(PostError::Unauthorized(
5147 "authentication required".to_string(),
Modified lib/post/features/lookup.rs lib/post/features/lookup.rs +1 −4 View lib/post/features/lookup.rs
@@ -40,10 +40,7 @@
4040}
4141
4242/// Resolve the channel hosting a specific posts collection.
43async fn channel_for_post_board_id(
44 svc: &PostService,
45 collection_id: Uuid,
46) -> PostResult<Uuid> {
43async fn channel_for_post_board_id(svc: &PostService, collection_id: Uuid) -> PostResult<Uuid> {
4744 let db = svc.db.reader();
4845 let board = posts_entity::Entity::find_by_id(collection_id)
4946 .one(&db)
Modified lib/post/handler/post/archive.rs lib/post/handler/post/archive.rs +2 −2 View lib/post/handler/post/archive.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let view = svc.archive_post(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(view))
Modified lib/post/handler/post/close.rs lib/post/handler/post/close.rs +2 −2 View lib/post/handler/post/close.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let view = svc.close_post(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(view))
Modified lib/post/handler/post/delete.rs lib/post/handler/post/delete.rs +2 −2 View lib/post/handler/post/delete.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 svc.delete_post(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(Value::Null))
Modified lib/post/handler/post/get.rs lib/post/handler/post/get.rs +2 −2 View lib/post/handler/post/get.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let view = svc.get_post(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(view))
Modified lib/post/handler/post/reopen.rs lib/post/handler/post/reopen.rs +2 −2 View lib/post/handler/post/reopen.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let view = svc.reopen_post(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(view))
Modified lib/post/handler/post/update.rs lib/post/handler/post/update.rs +2 −2 View lib/post/handler/post/update.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 let view = svc
3434 .update_post(claims.sub, channel_id, post.id, input.into_inner())
Modified lib/post/handler/post_label/bind.rs lib/post/handler/post_label/bind.rs +2 −2 View lib/post/handler/post_label/bind.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 svc.bind_post_label(claims.sub, channel_id, post.id, label_id)
3434 .await?;
Modified lib/post/handler/post_label/delete.rs lib/post/handler/post_label/delete.rs +2 −1 View lib/post/handler/post_label/delete.rs
@@ -26,6 +26,7 @@
2626 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2727 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2828 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
29 svc.delete_post_label(claims.sub, channel_id, label_id).await?;
29 svc.delete_post_label(claims.sub, channel_id, label_id)
30 .await?;
3031 Ok(AppResponseData::ok(Value::Null))
3132}
Modified lib/post/handler/post_label/list_for_post.rs lib/post/handler/post_label/list_for_post.rs +2 −2 View lib/post/handler/post_label/list_for_post.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let views = svc
3232 .list_post_labels_for_post(claims.sub, channel_id, post.id)
Modified lib/post/handler/post_label/unbind.rs lib/post/handler/post_label/unbind.rs +2 −2 View lib/post/handler/post_label/unbind.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 svc.unbind_post_label(claims.sub, channel_id, post.id, label_id)
3434 .await?;
Modified lib/post/handler/post_mention/create.rs lib/post/handler/post_mention/create.rs +2 −2 View lib/post/handler/post_mention/create.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 let view = svc
3434 .create_post_mention(claims.sub, channel_id, post.id, input.into_inner())
Modified lib/post/handler/post_mention/list.rs lib/post/handler/post_mention/list.rs +2 −2 View lib/post/handler/post_mention/list.rs
@@ -36,8 +36,8 @@
3636 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
3737 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
3838 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
39 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
40 .await?;
39 let post =
40 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
4141 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
4242 let views = svc
4343 .list_post_mentions(claims.sub, channel_id, post.id, q.limit, q.offset)
Modified lib/post/handler/post_reaction/create.rs lib/post/handler/post_reaction/create.rs +2 −2 View lib/post/handler/post_reaction/create.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 let view = svc
3434 .create_post_reaction(claims.sub, channel_id, post.id, input.into_inner())
Modified lib/post/handler/post_reaction/delete.rs lib/post/handler/post_reaction/delete.rs +2 −2 View lib/post/handler/post_reaction/delete.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 svc.delete_post_reaction(claims.sub, channel_id, post.id, reaction_id)
3434 .await?;
Modified lib/post/handler/post_reaction/list.rs lib/post/handler/post_reaction/list.rs +2 −2 View lib/post/handler/post_reaction/list.rs
@@ -36,8 +36,8 @@
3636 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
3737 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
3838 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
39 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
40 .await?;
39 let post =
40 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
4141 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
4242 let views = svc
4343 .list_post_reactions(claims.sub, channel_id, post.id, q.limit, q.offset)
Modified lib/post/handler/post_reply/create.rs lib/post/handler/post_reply/create.rs +2 −2 View lib/post/handler/post_reply/create.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 let view = svc
3434 .create_reply(claims.sub, channel_id, post.id, input.into_inner())
Modified lib/post/handler/post_reply/list.rs lib/post/handler/post_reply/list.rs +2 −2 View lib/post/handler/post_reply/list.rs
@@ -36,8 +36,8 @@
3636 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
3737 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
3838 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
39 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
40 .await?;
39 let post =
40 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
4141 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
4242 let page = svc
4343 .list_replies(claims.sub, channel_id, post.id, q.limit, q.offset)
Modified lib/post/handler/post_watch/delete.rs lib/post/handler/post_watch/delete.rs +2 −2 View lib/post/handler/post_watch/delete.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 svc.delete_watch(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(Value::Null))
Modified lib/post/handler/post_watch/get.rs lib/post/handler/post_watch/get.rs +2 −2 View lib/post/handler/post_watch/get.rs
@@ -25,8 +25,8 @@
2525 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2626 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2727 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
28 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
29 .await?;
28 let post =
29 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3030 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3131 let view = svc.get_watch(claims.sub, channel_id, post.id).await?;
3232 Ok(AppResponseData::ok(view))
Modified lib/post/handler/post_watch/upsert.rs lib/post/handler/post_watch/upsert.rs +2 −2 View lib/post/handler/post_watch/upsert.rs
@@ -27,8 +27,8 @@
2727 let space_id = space::features::lookup::lookup_space_by_name(&svc, &space_name).await?;
2828 space::features::authz::require_active_member(&svc, claims.sub, space_id).await?;
2929 let channel_id = crate::features::lookup::channel_for_post_board(&svc, space_id).await?;
30 let post = crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number)
31 .await?;
30 let post =
31 crate::features::post::usecase::resolve_post_by_number(&svc, channel_id, number).await?;
3232 let _channel_id = crate::features::lookup::channel_for_post(&svc, post.id).await?;
3333 let view = svc
3434 .upsert_watch(claims.sub, channel_id, post.id, input.into_inner())
Modified lib/post/service.rs lib/post/service.rs +6 −1 View lib/post/service.rs
@@ -26,7 +26,12 @@
2626 jwt: JwtState,
2727 storage: Arc<dyn StorageRepository>,
2828 ) -> Self {
29 Self { db, kv, jwt, storage }
29 Self {
30 db,
31 kv,
32 jwt,
33 storage,
34 }
3035 }
3136}
3237