4 #[derive(Serialize, Deserialize)]
5 pub struct GetCommunity {
11 #[derive(Serialize, Deserialize)]
12 pub struct GetCommunityResponse {
14 community: CommunityView,
15 moderators: Vec<CommunityModeratorView>,
16 admins: Vec<UserView>,
20 #[derive(Serialize, Deserialize)]
21 pub struct CreateCommunity {
24 description: Option<String>,
30 #[derive(Serialize, Deserialize, Clone)]
31 pub struct CommunityResponse {
33 pub community: CommunityView
36 #[derive(Serialize, Deserialize)]
37 pub struct ListCommunities {
44 #[derive(Serialize, Deserialize)]
45 pub struct ListCommunitiesResponse {
47 communities: Vec<CommunityView>
50 #[derive(Serialize, Deserialize, Clone)]
51 pub struct BanFromCommunity {
52 pub community_id: i32,
55 reason: Option<String>,
60 #[derive(Serialize, Deserialize)]
61 pub struct BanFromCommunityResponse {
67 #[derive(Serialize, Deserialize)]
68 pub struct AddModToCommunity {
69 pub community_id: i32,
75 #[derive(Serialize, Deserialize)]
76 pub struct AddModToCommunityResponse {
78 moderators: Vec<CommunityModeratorView>,
81 #[derive(Serialize, Deserialize)]
82 pub struct EditCommunity {
86 description: Option<String>,
88 removed: Option<bool>,
89 deleted: Option<bool>,
91 reason: Option<String>,
96 #[derive(Serialize, Deserialize)]
97 pub struct FollowCommunity {
103 #[derive(Serialize, Deserialize)]
104 pub struct GetFollowedCommunities {
108 #[derive(Serialize, Deserialize)]
109 pub struct GetFollowedCommunitiesResponse {
111 communities: Vec<CommunityFollowerView>
114 #[derive(Serialize, Deserialize)]
115 pub struct TransferCommunity {
121 impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
122 fn perform(&self) -> Result<GetCommunityResponse, Error> {
123 let data: &GetCommunity = &self.data;
124 let conn = establish_connection();
126 let user_id: Option<i32> = match &data.auth {
128 match Claims::decode(&auth) {
130 let user_id = claims.claims.id;
139 let community_id = match data.id {
141 None => Community::read_from_name(&conn, data.name.to_owned().unwrap_or("main".to_string()))?.id
144 let community_view = match CommunityView::read(&conn, community_id, user_id) {
145 Ok(community) => community,
147 return Err(APIError::err(&self.op, "couldnt_find_community"))?
151 let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
152 Ok(moderators) => moderators,
154 return Err(APIError::err(&self.op, "couldnt_find_community"))?
158 let site_creator_id = Site::read(&conn, 1)?.creator_id;
159 let mut admins = UserView::admins(&conn)?;
160 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
161 let creator_user = admins.remove(creator_index);
162 admins.insert(0, creator_user);
166 GetCommunityResponse {
167 op: self.op.to_string(),
168 community: community_view,
169 moderators: moderators,
176 impl Perform<CommunityResponse> for Oper<CreateCommunity> {
177 fn perform(&self) -> Result<CommunityResponse, Error> {
178 let data: &CreateCommunity = &self.data;
179 let conn = establish_connection();
181 let claims = match Claims::decode(&data.auth) {
182 Ok(claims) => claims.claims,
184 return Err(APIError::err(&self.op, "not_logged_in"))?
188 if has_slurs(&data.name) ||
189 has_slurs(&data.title) ||
190 (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
191 return Err(APIError::err(&self.op, "no_slurs"))?
194 let user_id = claims.id;
196 // Check for a site ban
197 if UserView::read(&conn, user_id)?.banned {
198 return Err(APIError::err(&self.op, "site_ban"))?
201 // When you create a community, make sure the user becomes a moderator and a follower
202 let community_form = CommunityForm {
203 name: data.name.to_owned(),
204 title: data.title.to_owned(),
205 description: data.description.to_owned(),
206 category_id: data.category_id,
214 let inserted_community = match Community::create(&conn, &community_form) {
215 Ok(community) => community,
217 return Err(APIError::err(&self.op, "community_already_exists"))?
221 let community_moderator_form = CommunityModeratorForm {
222 community_id: inserted_community.id,
226 let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
229 return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
233 let community_follower_form = CommunityFollowerForm {
234 community_id: inserted_community.id,
238 let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
241 return Err(APIError::err(&self.op, "community_follower_already_exists"))?
245 let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
249 op: self.op.to_string(),
250 community: community_view
256 impl Perform<CommunityResponse> for Oper<EditCommunity> {
257 fn perform(&self) -> Result<CommunityResponse, Error> {
258 let data: &EditCommunity = &self.data;
260 if has_slurs(&data.name) || has_slurs(&data.title) {
261 return Err(APIError::err(&self.op, "no_slurs"))?
264 let conn = establish_connection();
266 let claims = match Claims::decode(&data.auth) {
267 Ok(claims) => claims.claims,
269 return Err(APIError::err(&self.op, "not_logged_in"))?
273 let user_id = claims.id;
275 // Check for a site ban
276 if UserView::read(&conn, user_id)?.banned {
277 return Err(APIError::err(&self.op, "site_ban"))?
281 let mut editors: Vec<i32> = Vec::new();
283 &mut CommunityModeratorView::for_community(&conn, data.edit_id)
290 &mut UserView::admins(&conn)
296 if !editors.contains(&user_id) {
297 return Err(APIError::err(&self.op, "no_community_edit_allowed"))?
300 let community_form = CommunityForm {
301 name: data.name.to_owned(),
302 title: data.title.to_owned(),
303 description: data.description.to_owned(),
304 category_id: data.category_id.to_owned(),
306 removed: data.removed.to_owned(),
307 deleted: data.deleted.to_owned(),
309 updated: Some(naive_now())
312 let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
313 Ok(community) => community,
315 return Err(APIError::err(&self.op, "couldnt_update_community"))?
320 if let Some(removed) = data.removed.to_owned() {
321 let expires = match data.expires {
322 Some(time) => Some(naive_from_unix(time)),
325 let form = ModRemoveCommunityForm {
326 mod_user_id: user_id,
327 community_id: data.edit_id,
328 removed: Some(removed),
329 reason: data.reason.to_owned(),
332 ModRemoveCommunity::create(&conn, &form)?;
335 let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
339 op: self.op.to_string(),
340 community: community_view
346 impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
347 fn perform(&self) -> Result<ListCommunitiesResponse, Error> {
348 let data: &ListCommunities = &self.data;
349 let conn = establish_connection();
351 let user_claims: Option<Claims> = match &data.auth {
353 match Claims::decode(&auth) {
363 let user_id = match &user_claims {
364 Some(claims) => Some(claims.id),
368 let show_nsfw = match &user_claims {
369 Some(claims) => claims.show_nsfw,
373 let sort = SortType::from_str(&data.sort)?;
375 let communities: Vec<CommunityView> = CommunityView::list(
386 ListCommunitiesResponse {
387 op: self.op.to_string(),
388 communities: communities
395 impl Perform<CommunityResponse> for Oper<FollowCommunity> {
396 fn perform(&self) -> Result<CommunityResponse, Error> {
397 let data: &FollowCommunity = &self.data;
398 let conn = establish_connection();
400 let claims = match Claims::decode(&data.auth) {
401 Ok(claims) => claims.claims,
403 return Err(APIError::err(&self.op, "not_logged_in"))?
407 let user_id = claims.id;
409 let community_follower_form = CommunityFollowerForm {
410 community_id: data.community_id,
415 match CommunityFollower::follow(&conn, &community_follower_form) {
418 return Err(APIError::err(&self.op, "community_follower_already_exists"))?
422 match CommunityFollower::ignore(&conn, &community_follower_form) {
425 return Err(APIError::err(&self.op, "community_follower_already_exists"))?
430 let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?;
434 op: self.op.to_string(),
435 community: community_view
442 impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
443 fn perform(&self) -> Result<GetFollowedCommunitiesResponse, Error> {
444 let data: &GetFollowedCommunities = &self.data;
445 let conn = establish_connection();
447 let claims = match Claims::decode(&data.auth) {
448 Ok(claims) => claims.claims,
450 return Err(APIError::err(&self.op, "not_logged_in"))?
454 let user_id = claims.id;
456 let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) {
457 Ok(communities) => communities,
459 return Err(APIError::err(&self.op, "system_err_login"))?
465 GetFollowedCommunitiesResponse {
466 op: self.op.to_string(),
467 communities: communities
474 impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
475 fn perform(&self) -> Result<BanFromCommunityResponse, Error> {
476 let data: &BanFromCommunity = &self.data;
477 let conn = establish_connection();
479 let claims = match Claims::decode(&data.auth) {
480 Ok(claims) => claims.claims,
482 return Err(APIError::err(&self.op, "not_logged_in"))?
486 let user_id = claims.id;
488 let community_user_ban_form = CommunityUserBanForm {
489 community_id: data.community_id,
490 user_id: data.user_id,
494 match CommunityUserBan::ban(&conn, &community_user_ban_form) {
497 return Err(APIError::err(&self.op, "community_user_already_banned"))?
501 match CommunityUserBan::unban(&conn, &community_user_ban_form) {
504 return Err(APIError::err(&self.op, "community_user_already_banned"))?
510 let expires = match data.expires {
511 Some(time) => Some(naive_from_unix(time)),
515 let form = ModBanFromCommunityForm {
516 mod_user_id: user_id,
517 other_user_id: data.user_id,
518 community_id: data.community_id,
519 reason: data.reason.to_owned(),
520 banned: Some(data.ban),
523 ModBanFromCommunity::create(&conn, &form)?;
525 let user_view = UserView::read(&conn, data.user_id)?;
528 BanFromCommunityResponse {
529 op: self.op.to_string(),
537 impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
538 fn perform(&self) -> Result<AddModToCommunityResponse, Error> {
539 let data: &AddModToCommunity = &self.data;
540 let conn = establish_connection();
542 let claims = match Claims::decode(&data.auth) {
543 Ok(claims) => claims.claims,
545 return Err(APIError::err(&self.op, "not_logged_in"))?
549 let user_id = claims.id;
551 let community_moderator_form = CommunityModeratorForm {
552 community_id: data.community_id,
553 user_id: data.user_id
557 match CommunityModerator::join(&conn, &community_moderator_form) {
560 return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
564 match CommunityModerator::leave(&conn, &community_moderator_form) {
567 return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
573 let form = ModAddCommunityForm {
574 mod_user_id: user_id,
575 other_user_id: data.user_id,
576 community_id: data.community_id,
577 removed: Some(!data.added),
579 ModAddCommunity::create(&conn, &form)?;
581 let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?;
584 AddModToCommunityResponse {
585 op: self.op.to_string(),
586 moderators: moderators,
592 impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
593 fn perform(&self) -> Result<GetCommunityResponse, Error> {
594 let data: &TransferCommunity = &self.data;
595 let conn = establish_connection();
597 let claims = match Claims::decode(&data.auth) {
598 Ok(claims) => claims.claims,
600 return Err(APIError::err(&self.op, "not_logged_in"))?
604 let user_id = claims.id;
606 let read_community = Community::read(&conn, data.community_id)?;
608 // Make sure user is the creator
609 if read_community.creator_id != user_id {
610 return Err(APIError::err(&self.op, "not_an_admin"))?
613 let community_form = CommunityForm {
614 name: read_community.name,
615 title: read_community.title,
616 description: read_community.description,
617 category_id: read_community.category_id,
618 creator_id: data.user_id,
621 nsfw: read_community.nsfw,
622 updated: Some(naive_now())
625 let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
626 Ok(community) => community,
628 return Err(APIError::err(&self.op, "couldnt_update_community"))?
632 // You also have to re-do the community_moderator table, reordering it.
633 let mut community_mods = CommunityModeratorView::for_community(&conn, data.community_id)?;
634 let creator_index = community_mods.iter().position(|r| r.user_id == data.user_id).unwrap();
635 let creator_user = community_mods.remove(creator_index);
636 community_mods.insert(0, creator_user);
638 CommunityModerator::delete_for_community(&conn, data.community_id)?;
640 for cmod in &community_mods {
642 let community_moderator_form = CommunityModeratorForm {
643 community_id: cmod.community_id,
644 user_id: cmod.user_id
647 let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
650 return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
656 let form = ModAddCommunityForm {
657 mod_user_id: user_id,
658 other_user_id: data.user_id,
659 community_id: data.community_id,
660 removed: Some(false),
662 ModAddCommunity::create(&conn, &form)?;
664 let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) {
665 Ok(community) => community,
667 return Err(APIError::err(&self.op, "couldnt_find_community"))?
671 let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) {
672 Ok(moderators) => moderators,
674 return Err(APIError::err(&self.op, "couldnt_find_community"))?
678 let site_creator_id = Site::read(&conn, 1)?.creator_id;
679 let mut admins = UserView::admins(&conn)?;
680 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
681 let creator_user = admins.remove(creator_index);
682 admins.insert(0, creator_user);
686 GetCommunityResponse {
687 op: self.op.to_string(),
688 community: community_view,
689 moderators: moderators,