X-Git-Url: http://these/git/?a=blobdiff_plain;f=server%2Fsrc%2Fapi%2Fcommunity.rs;h=3fc67eb348f766905ea14e0b701bed2e9009a50d;hb=dc94e58cbf7e7de10d97331a3056380a3416e0b0;hp=618122b9868a1aab8c1a32ef16e455f974b732ae;hpb=790b944031f9433be765936763d848ffa6e1b496;p=lemmy.git diff --git a/server/src/api/community.rs b/server/src/api/community.rs index 618122b9..3fc67eb3 100644 --- a/server/src/api/community.rs +++ b/server/src/api/community.rs @@ -1,18 +1,44 @@ use super::*; -use crate::is_valid_community_name; +use crate::{ + api::{APIError, Oper, Perform}, + apub::{ + extensions::signatures::generate_actor_keypair, + make_apub_endpoint, + ActorType, + EndpointType, + }, + db::{Bannable, Crud, Followable, Joinable, SortType}, + is_valid_community_name, + naive_from_unix, + naive_now, + slur_check, + slurs_vec_to_str, + websocket::{ + server::{JoinCommunityRoom, SendCommunityRoomMessage}, + UserOperation, + WebsocketInfo, + }, +}; +use diesel::{ + r2d2::{ConnectionManager, Pool}, + PgConnection, +}; +use failure::Error; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Serialize, Deserialize)] pub struct GetCommunity { id: Option, - name: Option, + pub name: Option, auth: Option, } #[derive(Serialize, Deserialize)] pub struct GetCommunityResponse { pub community: CommunityView, - moderators: Vec, - admins: Vec, + pub moderators: Vec, + pub admins: Vec, pub online: usize, } @@ -31,17 +57,17 @@ pub struct CommunityResponse { pub community: CommunityView, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ListCommunities { - sort: String, - page: Option, - limit: Option, - auth: Option, + pub sort: String, + pub page: Option, + pub limit: Option, + pub auth: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ListCommunitiesResponse { - communities: Vec, + pub communities: Vec, } #[derive(Serialize, Deserialize, Clone)] @@ -135,25 +161,25 @@ impl Perform for Oper { let conn = pool.get()?; - let community_id = match data.id { - Some(id) => id, + let community = match data.id { + Some(id) => Community::read(&conn, id)?, None => { match Community::read_from_name( &conn, - data.name.to_owned().unwrap_or_else(|| "main".to_string()), + &data.name.to_owned().unwrap_or_else(|| "main".to_string()), ) { - Ok(community) => community.id, + Ok(community) => community, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), } } }; - let community_view = match CommunityView::read(&conn, community_id, user_id) { + let community_view = match CommunityView::read(&conn, community.id, user_id) { Ok(community) => community, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; - let moderators = match CommunityModeratorView::for_community(&conn, community_id) { + let moderators = match CommunityModeratorView::for_community(&conn, community.id) { Ok(moderators) => moderators, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; @@ -166,8 +192,10 @@ impl Perform for Oper { let online = if let Some(ws) = websocket_info { if let Some(id) = ws.id { - ws.chatserver - .do_send(JoinCommunityRoom { community_id, id }); + ws.chatserver.do_send(JoinCommunityRoom { + community_id: community.id, + id, + }); } // TODO @@ -235,6 +263,8 @@ impl Perform for Oper { } // When you create a community, make sure the user becomes a moderator and a follower + let keypair = generate_actor_keypair()?; + let community_form = CommunityForm { name: data.name.to_owned(), title: data.title.to_owned(), @@ -245,6 +275,12 @@ impl Perform for Oper { deleted: None, nsfw: data.nsfw, updated: None, + actor_id: make_apub_endpoint(EndpointType::Community, &data.name).to_string(), + local: true, + private_key: Some(keypair.private_key), + public_key: Some(keypair.public_key), + last_refreshed_at: None, + published: None, }; let inserted_community = match Community::create(&conn, &community_form) { @@ -320,7 +356,8 @@ impl Perform for Oper { let conn = pool.get()?; // Check for a site ban - if UserView::read(&conn, user_id)?.banned { + let user = User_::read(&conn, user_id)?; + if user.banned { return Err(APIError::err("site_ban").into()); } @@ -337,6 +374,8 @@ impl Perform for Oper { return Err(APIError::err("no_community_edit_allowed").into()); } + let read_community = Community::read(&conn, data.edit_id)?; + let community_form = CommunityForm { name: data.name.to_owned(), title: data.title.to_owned(), @@ -347,9 +386,15 @@ impl Perform for Oper { deleted: data.deleted.to_owned(), nsfw: data.nsfw, updated: Some(naive_now()), + actor_id: read_community.actor_id, + local: read_community.local, + private_key: read_community.private_key, + public_key: read_community.public_key, + last_refreshed_at: None, + published: None, }; - let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { + let updated_community = match Community::update(&conn, data.edit_id, &community_form) { Ok(community) => community, Err(_e) => return Err(APIError::err("couldnt_update_community").into()), }; @@ -370,6 +415,20 @@ impl Perform for Oper { ModRemoveCommunity::create(&conn, &form)?; } + if let Some(deleted) = data.deleted.to_owned() { + if deleted { + updated_community.send_delete(&user, &conn)?; + } else { + updated_community.send_undo_delete(&user, &conn)?; + } + } else if let Some(removed) = data.removed.to_owned() { + if removed { + updated_community.send_remove(&user, &conn)?; + } else { + updated_community.send_undo_remove(&user, &conn)?; + } + } + let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?; let res = CommunityResponse { @@ -456,23 +515,41 @@ impl Perform for Oper { let user_id = claims.id; + let conn = pool.get()?; + + let community = Community::read(&conn, data.community_id)?; let community_follower_form = CommunityFollowerForm { community_id: data.community_id, user_id, }; - let conn = pool.get()?; - - if data.follow { - match CommunityFollower::follow(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), - }; + if community.local { + if data.follow { + match CommunityFollower::follow(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + }; + } else { + match CommunityFollower::unfollow(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + }; + } } else { - match CommunityFollower::ignore(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), - }; + let user = User_::read(&conn, user_id)?; + + if data.follow { + // Dont actually add to the community followers here, because you need + // to wait for the accept + user.send_follow(&community.actor_id, &conn)?; + } else { + user.send_unfollow(&community.actor_id, &conn)?; + match CommunityFollower::unfollow(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + }; + } + // TODO: this needs to return a "pending" state, until Accept is received from the remote server } let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?; @@ -684,11 +761,17 @@ impl Perform for Oper { title: read_community.title, description: read_community.description, category_id: read_community.category_id, - creator_id: data.user_id, + creator_id: data.user_id, // This makes the new user the community creator removed: None, deleted: None, nsfw: read_community.nsfw, updated: Some(naive_now()), + actor_id: read_community.actor_id, + local: read_community.local, + private_key: read_community.private_key, + public_key: read_community.public_key, + last_refreshed_at: None, + published: None, }; let _updated_community = match Community::update(&conn, data.community_id, &community_form) {