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 conn = pool.get()?;
|
||||||
|
|
||||||
let community = Community::read(&conn, data.community_id)?;
|
let community = Community::read(&conn, data.community_id)?;
|
||||||
if community.local {
|
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
community_id: data.community_id,
|
community_id: data.community_id,
|
||||||
user_id,
|
user_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if community.local {
|
||||||
if data.follow {
|
if data.follow {
|
||||||
match CommunityFollower::follow(&conn, &community_follower_form) {
|
match CommunityFollower::follow(&conn, &community_follower_form) {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
|
@ -501,9 +501,19 @@ impl Perform for Oper<FollowCommunity> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: still have to implement unfollow
|
|
||||||
let user = User_::read(&conn, user_id)?;
|
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)?;
|
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
|
// 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(),
|
.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 {
|
impl FromApub for CommunityForm {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use super::*;
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub enum CommunityAcceptedObjects {
|
pub enum CommunityAcceptedObjects {
|
||||||
Follow(Follow),
|
Follow(Follow),
|
||||||
|
Undo(Undo),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Consolidate community and user inboxes into a single shared one
|
// TODO Consolidate community and user inboxes into a single shared one
|
||||||
|
@ -25,6 +26,9 @@ pub async fn community_inbox(
|
||||||
CommunityAcceptedObjects::Follow(f) => {
|
CommunityAcceptedObjects::Follow(f) => {
|
||||||
handle_follow(&f, &request, &community_name, db, chat_server)
|
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())
|
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,
|
// These two have default impls, since currently a community can't follow anything,
|
||||||
// and a user can't be followed (yet)
|
// and a user can't be followed (yet)
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn send_follow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error> {
|
fn send_follow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error>;
|
||||||
Err(format_err!("Follow not implemented."))
|
fn send_unfollow(&self, follow_actor_id: &str, conn: &PgConnection) -> Result<(), Error>;
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn send_accept_follow(&self, follow: &Follow, conn: &PgConnection) -> Result<(), Error> {
|
fn send_accept_follow(&self, follow: &Follow, conn: &PgConnection) -> Result<(), Error>;
|
||||||
Err(format_err!("Accept not implemented."))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_delete(&self, creator: &User_, 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>;
|
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_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
|
||||||
fn send_undo_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.
|
/// For a given community, returns the inboxes of all followers.
|
||||||
fn get_follower_inboxes(&self, conn: &PgConnection) -> Result<Vec<String>, Error> {
|
fn get_follower_inboxes(&self, conn: &PgConnection) -> Result<Vec<String>, Error>;
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move these to the db rows
|
// TODO move these to the db rows
|
||||||
fn get_inbox_url(&self) -> String {
|
fn get_inbox_url(&self) -> String {
|
||||||
|
|
|
@ -91,6 +91,54 @@ impl ActorType for User_ {
|
||||||
Ok(())
|
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> {
|
fn send_delete(&self, _creator: &User_, _conn: &PgConnection) -> Result<(), Error> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -106,6 +154,14 @@ impl ActorType for User_ {
|
||||||
fn send_undo_remove(&self, _creator: &User_, _conn: &PgConnection) -> Result<(), Error> {
|
fn send_undo_remove(&self, _creator: &User_, _conn: &PgConnection) -> Result<(), Error> {
|
||||||
unimplemented!()
|
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 {
|
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());
|
).then(d => d.json());
|
||||||
|
|
||||||
expect(followedCommunitiesRes.communities[1].community_local).toBe(false);
|
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