2 use diesel::PgConnection;
5 #[derive(Serialize, Deserialize)]
6 pub struct GetCommunity {
8 pub name: Option<String>,
12 #[derive(Serialize, Deserialize)]
13 pub struct GetCommunityResponse {
14 pub community: CommunityView,
15 pub moderators: Vec<CommunityModeratorView>,
16 pub admins: Vec<UserView>,
20 #[derive(Serialize, Deserialize)]
21 pub struct CreateCommunity {
24 description: Option<String>,
30 #[derive(Serialize, Deserialize, Clone)]
31 pub struct CommunityResponse {
32 pub community: CommunityView,
35 #[derive(Serialize, Deserialize)]
36 pub struct ListCommunities {
43 #[derive(Serialize, Deserialize, Debug)]
44 pub struct ListCommunitiesResponse {
45 pub communities: Vec<CommunityView>,
48 #[derive(Serialize, Deserialize, Clone)]
49 pub struct BanFromCommunity {
50 pub community_id: i32,
53 reason: Option<String>,
58 #[derive(Serialize, Deserialize)]
59 pub struct BanFromCommunityResponse {
64 #[derive(Serialize, Deserialize)]
65 pub struct AddModToCommunity {
66 pub community_id: i32,
72 #[derive(Serialize, Deserialize)]
73 pub struct AddModToCommunityResponse {
74 moderators: Vec<CommunityModeratorView>,
77 #[derive(Serialize, Deserialize)]
78 pub struct EditCommunity {
82 description: Option<String>,
84 removed: Option<bool>,
85 deleted: Option<bool>,
87 reason: Option<String>,
92 #[derive(Serialize, Deserialize)]
93 pub struct FollowCommunity {
99 #[derive(Serialize, Deserialize)]
100 pub struct GetFollowedCommunities {
104 #[derive(Serialize, Deserialize)]
105 pub struct GetFollowedCommunitiesResponse {
106 communities: Vec<CommunityFollowerView>,
109 #[derive(Serialize, Deserialize)]
110 pub struct TransferCommunity {
116 impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
117 fn perform(&self, conn: &PgConnection) -> Result<GetCommunityResponse, Error> {
118 let data: &GetCommunity = &self.data;
120 let user_id: Option<i32> = match &data.auth {
121 Some(auth) => match Claims::decode(&auth) {
123 let user_id = claims.claims.id;
131 let community_id = match data.id {
134 match Community::read_from_name(
136 data.name.to_owned().unwrap_or_else(|| "main".to_string()),
138 Ok(community) => community.id,
139 Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
144 let community_view = match CommunityView::read(&conn, community_id, user_id) {
145 Ok(community) => community,
146 Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
149 let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
150 Ok(moderators) => moderators,
151 Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
154 let site_creator_id = Site::read(&conn, 1)?.creator_id;
155 let mut admins = UserView::admins(&conn)?;
156 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
157 let creator_user = admins.remove(creator_index);
158 admins.insert(0, creator_user);
161 Ok(GetCommunityResponse {
162 community: community_view,
170 impl Perform<CommunityResponse> for Oper<CreateCommunity> {
171 fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> {
172 let data: &CreateCommunity = &self.data;
174 let claims = match Claims::decode(&data.auth) {
175 Ok(claims) => claims.claims,
176 Err(_e) => return Err(APIError::err("not_logged_in").into()),
179 if let Err(slurs) = slur_check(&data.name) {
180 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
183 if let Err(slurs) = slur_check(&data.title) {
184 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
187 if let Some(description) = &data.description {
188 if let Err(slurs) = slur_check(description) {
189 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
193 let user_id = claims.id;
195 // Check for a site ban
196 if UserView::read(&conn, user_id)?.banned {
197 return Err(APIError::err("site_ban").into());
200 // When you create a community, make sure the user becomes a moderator and a follower
201 let community_form = CommunityForm {
202 name: data.name.to_owned(),
203 title: data.title.to_owned(),
204 description: data.description.to_owned(),
205 category_id: data.category_id,
213 let inserted_community = match Community::create(&conn, &community_form) {
214 Ok(community) => community,
215 Err(_e) => return Err(APIError::err("community_already_exists").into()),
218 let community_moderator_form = CommunityModeratorForm {
219 community_id: inserted_community.id,
223 let _inserted_community_moderator =
224 match CommunityModerator::join(&conn, &community_moderator_form) {
226 Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()),
229 let community_follower_form = CommunityFollowerForm {
230 community_id: inserted_community.id,
234 let _inserted_community_follower =
235 match CommunityFollower::follow(&conn, &community_follower_form) {
237 Err(_e) => return Err(APIError::err("community_follower_already_exists").into()),
240 let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
242 Ok(CommunityResponse {
243 community: community_view,
248 impl Perform<CommunityResponse> for Oper<EditCommunity> {
249 fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> {
250 let data: &EditCommunity = &self.data;
252 if let Err(slurs) = slur_check(&data.name) {
253 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
256 if let Err(slurs) = slur_check(&data.title) {
257 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
260 if let Some(description) = &data.description {
261 if let Err(slurs) = slur_check(description) {
262 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
266 let claims = match Claims::decode(&data.auth) {
267 Ok(claims) => claims.claims,
268 Err(_e) => return Err(APIError::err("not_logged_in").into()),
271 let user_id = claims.id;
273 // Check for a site ban
274 if UserView::read(&conn, user_id)?.banned {
275 return Err(APIError::err("site_ban").into());
279 let mut editors: Vec<i32> = Vec::new();
281 &mut CommunityModeratorView::for_community(&conn, data.edit_id)?
286 editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
287 if !editors.contains(&user_id) {
288 return Err(APIError::err("no_community_edit_allowed").into());
291 let community_form = CommunityForm {
292 name: data.name.to_owned(),
293 title: data.title.to_owned(),
294 description: data.description.to_owned(),
295 category_id: data.category_id.to_owned(),
297 removed: data.removed.to_owned(),
298 deleted: data.deleted.to_owned(),
300 updated: Some(naive_now()),
303 let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
304 Ok(community) => community,
305 Err(_e) => return Err(APIError::err("couldnt_update_community").into()),
309 if let Some(removed) = data.removed.to_owned() {
310 let expires = match data.expires {
311 Some(time) => Some(naive_from_unix(time)),
314 let form = ModRemoveCommunityForm {
315 mod_user_id: user_id,
316 community_id: data.edit_id,
317 removed: Some(removed),
318 reason: data.reason.to_owned(),
321 ModRemoveCommunity::create(&conn, &form)?;
324 let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
326 Ok(CommunityResponse {
327 community: community_view,
332 impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
333 fn perform(&self, conn: &PgConnection) -> Result<ListCommunitiesResponse, Error> {
334 let data: &ListCommunities = &self.data;
336 let user_claims: Option<Claims> = match &data.auth {
337 Some(auth) => match Claims::decode(&auth) {
338 Ok(claims) => Some(claims.claims),
344 let user_id = match &user_claims {
345 Some(claims) => Some(claims.id),
349 let show_nsfw = match &user_claims {
350 Some(claims) => claims.show_nsfw,
354 let sort = SortType::from_str(&data.sort)?;
356 let communities = CommunityQueryBuilder::create(&conn)
359 .show_nsfw(show_nsfw)
365 Ok(ListCommunitiesResponse { communities })
369 impl Perform<CommunityResponse> for Oper<FollowCommunity> {
370 fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> {
371 let data: &FollowCommunity = &self.data;
373 let claims = match Claims::decode(&data.auth) {
374 Ok(claims) => claims.claims,
375 Err(_e) => return Err(APIError::err("not_logged_in").into()),
378 let user_id = claims.id;
380 let community_follower_form = CommunityFollowerForm {
381 community_id: data.community_id,
386 match CommunityFollower::follow(&conn, &community_follower_form) {
388 Err(_e) => return Err(APIError::err("community_follower_already_exists").into()),
391 match CommunityFollower::ignore(&conn, &community_follower_form) {
393 Err(_e) => return Err(APIError::err("community_follower_already_exists").into()),
397 let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?;
399 Ok(CommunityResponse {
400 community: community_view,
405 impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
406 fn perform(&self, conn: &PgConnection) -> Result<GetFollowedCommunitiesResponse, Error> {
407 let data: &GetFollowedCommunities = &self.data;
409 let claims = match Claims::decode(&data.auth) {
410 Ok(claims) => claims.claims,
411 Err(_e) => return Err(APIError::err("not_logged_in").into()),
414 let user_id = claims.id;
416 let communities: Vec<CommunityFollowerView> =
417 match CommunityFollowerView::for_user(&conn, user_id) {
418 Ok(communities) => communities,
419 Err(_e) => return Err(APIError::err("system_err_login").into()),
423 Ok(GetFollowedCommunitiesResponse { communities })
427 impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
428 fn perform(&self, conn: &PgConnection) -> Result<BanFromCommunityResponse, Error> {
429 let data: &BanFromCommunity = &self.data;
431 let claims = match Claims::decode(&data.auth) {
432 Ok(claims) => claims.claims,
433 Err(_e) => return Err(APIError::err("not_logged_in").into()),
436 let user_id = claims.id;
438 let community_user_ban_form = CommunityUserBanForm {
439 community_id: data.community_id,
440 user_id: data.user_id,
444 match CommunityUserBan::ban(&conn, &community_user_ban_form) {
446 Err(_e) => return Err(APIError::err("community_user_already_banned").into()),
449 match CommunityUserBan::unban(&conn, &community_user_ban_form) {
451 Err(_e) => return Err(APIError::err("community_user_already_banned").into()),
456 let expires = match data.expires {
457 Some(time) => Some(naive_from_unix(time)),
461 let form = ModBanFromCommunityForm {
462 mod_user_id: user_id,
463 other_user_id: data.user_id,
464 community_id: data.community_id,
465 reason: data.reason.to_owned(),
466 banned: Some(data.ban),
469 ModBanFromCommunity::create(&conn, &form)?;
471 let user_view = UserView::read(&conn, data.user_id)?;
473 Ok(BanFromCommunityResponse {
480 impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
481 fn perform(&self, conn: &PgConnection) -> Result<AddModToCommunityResponse, Error> {
482 let data: &AddModToCommunity = &self.data;
484 let claims = match Claims::decode(&data.auth) {
485 Ok(claims) => claims.claims,
486 Err(_e) => return Err(APIError::err("not_logged_in").into()),
489 let user_id = claims.id;
491 let community_moderator_form = CommunityModeratorForm {
492 community_id: data.community_id,
493 user_id: data.user_id,
497 match CommunityModerator::join(&conn, &community_moderator_form) {
499 Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()),
502 match CommunityModerator::leave(&conn, &community_moderator_form) {
504 Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()),
509 let form = ModAddCommunityForm {
510 mod_user_id: user_id,
511 other_user_id: data.user_id,
512 community_id: data.community_id,
513 removed: Some(!data.added),
515 ModAddCommunity::create(&conn, &form)?;
517 let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?;
519 Ok(AddModToCommunityResponse { moderators })
523 impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
524 fn perform(&self, conn: &PgConnection) -> Result<GetCommunityResponse, Error> {
525 let data: &TransferCommunity = &self.data;
527 let claims = match Claims::decode(&data.auth) {
528 Ok(claims) => claims.claims,
529 Err(_e) => return Err(APIError::err("not_logged_in").into()),
532 let user_id = claims.id;
534 let read_community = Community::read(&conn, data.community_id)?;
536 let site_creator_id = Site::read(&conn, 1)?.creator_id;
537 let mut admins = UserView::admins(&conn)?;
538 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
539 let creator_user = admins.remove(creator_index);
540 admins.insert(0, creator_user);
542 // Make sure user is the creator, or an admin
543 if user_id != read_community.creator_id && !admins.iter().map(|a| a.id).any(|x| x == user_id) {
544 return Err(APIError::err("not_an_admin").into());
547 let community_form = CommunityForm {
548 name: read_community.name,
549 title: read_community.title,
550 description: read_community.description,
551 category_id: read_community.category_id,
552 creator_id: data.user_id,
555 nsfw: read_community.nsfw,
556 updated: Some(naive_now()),
559 let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
560 Ok(community) => community,
561 Err(_e) => return Err(APIError::err("couldnt_update_community").into()),
564 // You also have to re-do the community_moderator table, reordering it.
565 let mut community_mods = CommunityModeratorView::for_community(&conn, data.community_id)?;
566 let creator_index = community_mods
568 .position(|r| r.user_id == data.user_id)
570 let creator_user = community_mods.remove(creator_index);
571 community_mods.insert(0, creator_user);
573 CommunityModerator::delete_for_community(&conn, data.community_id)?;
575 for cmod in &community_mods {
576 let community_moderator_form = CommunityModeratorForm {
577 community_id: cmod.community_id,
578 user_id: cmod.user_id,
581 let _inserted_community_moderator =
582 match CommunityModerator::join(&conn, &community_moderator_form) {
584 Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()),
589 let form = ModAddCommunityForm {
590 mod_user_id: user_id,
591 other_user_id: data.user_id,
592 community_id: data.community_id,
593 removed: Some(false),
595 ModAddCommunity::create(&conn, &form)?;
597 let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) {
598 Ok(community) => community,
599 Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
602 let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) {
603 Ok(moderators) => moderators,
604 Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
608 Ok(GetCommunityResponse {
609 community: community_view,