mirror of
https://github.com/LemmyNet/lemmy
synced 2024-11-23 04:53:06 +00:00
Adding undo follow community.
This commit is contained in:
parent
fab22e3d8a
commit
b8b2398d32
6 changed files with 186 additions and 18 deletions
|
@ -483,12 +483,12 @@ impl Perform for Oper<FollowCommunity> {
|
|||
let conn = pool.get()?;
|
||||
|
||||
let community = Community::read(&conn, data.community_id)?;
|
||||
if community.local {
|
||||
let community_follower_form = CommunityFollowerForm {
|
||||
community_id: data.community_id,
|
||||
user_id,
|
||||
};
|
||||
|
||||
if community.local {
|
||||
if data.follow {
|
||||
match CommunityFollower::follow(&conn, &community_follower_form) {
|
||||
Ok(user) => user,
|
||||
|
@ -501,9 +501,19 @@ impl Perform for Oper<FollowCommunity> {
|
|||
};
|
||||
}
|
||||
} else {
|
||||
// TODO: still have to implement unfollow
|
||||
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::ignore(&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
|
||||
}
|
||||
|
||||
|
|
|
@ -289,6 +289,14 @@ impl ActorType for Community {
|
|||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn send_follow(&self, _follow_actor_id: &str, _conn: &PgConnection) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn send_unfollow(&self, _follow_actor_id: &str, _conn: &PgConnection) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromApub for CommunityForm {
|
||||
|
|
|
@ -4,6 +4,7 @@ use super::*;
|
|||
#[derive(Deserialize, Debug)]
|
||||
pub enum CommunityAcceptedObjects {
|
||||
Follow(Follow),
|
||||
Undo(Undo),
|
||||
}
|
||||
|
||||
// TODO Consolidate community and user inboxes into a single shared one
|
||||
|
@ -25,6 +26,9 @@ pub async fn community_inbox(
|
|||
CommunityAcceptedObjects::Follow(f) => {
|
||||
handle_follow(&f, &request, &community_name, db, chat_server)
|
||||
}
|
||||
CommunityAcceptedObjects::Undo(u) => {
|
||||
handle_undo_follow(&u, &request, &community_name, db, chat_server)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,3 +80,56 @@ fn handle_follow(
|
|||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
||||
fn handle_undo_follow(
|
||||
undo: &Undo,
|
||||
request: &HttpRequest,
|
||||
community_name: &str,
|
||||
db: DbPoolParam,
|
||||
_chat_server: ChatServerParam,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let follow = undo
|
||||
.undo_props
|
||||
.get_object_base_box()
|
||||
.to_owned()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
.into_concrete::<Follow>()?;
|
||||
|
||||
let user_uri = follow
|
||||
.follow_props
|
||||
.get_actor_xsd_any_uri()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let _community_uri = follow
|
||||
.follow_props
|
||||
.get_object_xsd_any_uri()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let conn = db.get()?;
|
||||
|
||||
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
||||
let community = Community::read_from_name(&conn, &community_name)?;
|
||||
|
||||
verify(&request, &user.public_key.unwrap())?;
|
||||
|
||||
// Insert the received activity into the activity table
|
||||
let activity_form = activity::ActivityForm {
|
||||
user_id: user.id,
|
||||
data: serde_json::to_value(&follow)?,
|
||||
local: false,
|
||||
updated: None,
|
||||
};
|
||||
activity::Activity::create(&conn, &activity_form)?;
|
||||
|
||||
let community_follower_form = CommunityFollowerForm {
|
||||
community_id: community.id,
|
||||
user_id: user.id,
|
||||
};
|
||||
|
||||
CommunityFollower::ignore(&conn, &community_follower_form).ok();
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
|
|
@ -233,14 +233,11 @@ pub trait ActorType {
|
|||
// These two have default impls, since currently a community can't follow anything,
|
||||
// and a user can't be followed (yet)
|
||||
#[allow(unused_variables)]
|
||||
fn send_follow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error> {
|
||||
Err(format_err!("Follow not implemented."))
|
||||
}
|
||||
fn send_follow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error>;
|
||||
fn send_unfollow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error>;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn send_accept_follow(&self, follow: &Follow, conn: &PgConnection) -> Result<(), Error> {
|
||||
Err(format_err!("Accept not implemented."))
|
||||
}
|
||||
fn send_accept_follow(&self, follow: &Follow, conn: &PgConnection) -> Result<(), Error>;
|
||||
|
||||
fn send_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
|
||||
fn send_undo_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
|
||||
|
@ -248,12 +245,8 @@ pub trait ActorType {
|
|||
fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
|
||||
fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
|
||||
|
||||
// TODO default because there is no user following yet.
|
||||
#[allow(unused_variables)]
|
||||
/// For a given community, returns the inboxes of all followers.
|
||||
fn get_follower_inboxes(&self, conn: &PgConnection) -> Result<Vec<String>, Error> {
|
||||
Ok(vec![])
|
||||
}
|
||||
fn get_follower_inboxes(&self, conn: &PgConnection) -> Result<Vec<String>, Error>;
|
||||
|
||||
// TODO move these to the db rows
|
||||
fn get_inbox_url(&self) -> String {
|
||||
|
|
|
@ -91,6 +91,54 @@ impl ActorType for User_ {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn send_unfollow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error> {
|
||||
let mut follow = Follow::new();
|
||||
|
||||
let id = format!("{}/follow/{}", self.actor_id, uuid::Uuid::new_v4());
|
||||
|
||||
follow
|
||||
.object_props
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(id)?;
|
||||
follow
|
||||
.follow_props
|
||||
.set_actor_xsd_any_uri(self.actor_id.to_owned())?
|
||||
.set_object_xsd_any_uri(follow_actor_id)?;
|
||||
let to = format!("{}/inbox", follow_actor_id);
|
||||
|
||||
// TODO
|
||||
// Undo that fake activity
|
||||
let undo_id = format!("{}/undo/follow/{}", self.actor_id, uuid::Uuid::new_v4());
|
||||
let mut undo = Undo::default();
|
||||
|
||||
undo
|
||||
.object_props
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(undo_id)?;
|
||||
|
||||
undo
|
||||
.undo_props
|
||||
.set_actor_xsd_any_uri(self.actor_id.to_owned())?
|
||||
.set_object_base_box(follow)?;
|
||||
|
||||
// Insert the sent activity into the activity table
|
||||
let activity_form = activity::ActivityForm {
|
||||
user_id: self.id,
|
||||
data: serde_json::to_value(&undo)?,
|
||||
local: true,
|
||||
updated: None,
|
||||
};
|
||||
activity::Activity::create(&conn, &activity_form)?;
|
||||
|
||||
send_activity(
|
||||
&undo,
|
||||
&self.private_key.as_ref().unwrap(),
|
||||
&follow_actor_id,
|
||||
vec![to],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_delete(&self, _creator: &User_, _conn: &PgConnection) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -106,6 +154,14 @@ impl ActorType for User_ {
|
|||
fn send_undo_remove(&self, _creator: &User_, _conn: &PgConnection) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn send_accept_follow(&self, _follow: &Follow, _conn: &PgConnection) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_follower_inboxes(&self, _conn: &PgConnection) -> Result<Vec<String>, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromApub for UserForm {
|
||||
|
|
44
ui/src/api_tests/api.spec.ts
vendored
44
ui/src/api_tests/api.spec.ts
vendored
|
@ -140,6 +140,50 @@ describe('main', () => {
|
|||
).then(d => d.json());
|
||||
|
||||
expect(followedCommunitiesRes.communities[1].community_local).toBe(false);
|
||||
|
||||
// Test out unfollowing
|
||||
let unfollowForm: FollowCommunityForm = {
|
||||
community_id: searchResponse.communities[0].id,
|
||||
follow: false,
|
||||
auth: lemmyAlphaAuth,
|
||||
};
|
||||
|
||||
let unfollowRes: CommunityResponse = await fetch(
|
||||
`${lemmyAlphaApiUrl}/community/follow`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: wrapper(unfollowForm),
|
||||
}
|
||||
).then(d => d.json());
|
||||
|
||||
// Check that you are unsubscribed to it locally
|
||||
let followedCommunitiesResAgain: GetFollowedCommunitiesResponse = await fetch(
|
||||
followedCommunitiesUrl,
|
||||
{
|
||||
method: 'GET',
|
||||
}
|
||||
).then(d => d.json());
|
||||
|
||||
expect(followedCommunitiesResAgain.communities.length).toBe(1);
|
||||
|
||||
// Follow again, for other tests
|
||||
let followResAgain: CommunityResponse = await fetch(
|
||||
`${lemmyAlphaApiUrl}/community/follow`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: wrapper(followForm),
|
||||
}
|
||||
).then(d => d.json());
|
||||
|
||||
// Make sure the follow response went through
|
||||
expect(followResAgain.community.local).toBe(false);
|
||||
expect(followResAgain.community.name).toBe('main');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue