unfollows,
getComments,
getCommentParentId,
+ resolveCommunity,
} from './shared';
let postRes: PostResponse;
test('A and G subscribe to B (center) A posts, G mentions B, it gets announced to A', async () => {
// Create a local post
- let alphaCommunity = await createCommunity(alpha, "main");
- let alphaPost = await createPost(alpha, alphaCommunity.community_view.community.id);
+ let alphaCommunity = (await resolveCommunity(alpha, "!main@lemmy-alpha:8541")).community.unwrap();
+ let alphaPost = await createPost(alpha, alphaCommunity.community.id);
expect(alphaPost.post_view.community.local).toBe(true);
// Make sure gamma sees it
c => c.community.local == false
).community.id;
expect(remoteCommunityId).toBeDefined();
- expect(site.my_user.unwrap().follows.length).toBe(1);
+ expect(site.my_user.unwrap().follows.length).toBe(2);
// Test an unfollow
let unfollow = await followCommunity(alpha, false, remoteCommunityId);
// Make sure you are unsubbed locally
let siteUnfollowCheck = await getSite(alpha);
- expect(siteUnfollowCheck.my_user.unwrap().follows.length).toBe(0);
+ expect(siteUnfollowCheck.my_user.unwrap().follows.length).toBe(1);
});
registerUser,
API,
getSite,
- unfollows
+ unfollows,
+ resolveCommunity
} from './shared';
let betaCommunity: CommunityView;
});
test('Remove a post from admin and community on different instance', async () => {
- let postRes = await createPost(gamma, betaCommunity.community.id);
+ let gammaCommunity = await resolveCommunity(gamma, betaCommunity.community.actor_id);
+ let postRes = await createPost(gamma, gammaCommunity.community.unwrap().community.id);
let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post.unwrap();
let removedPost = await removePost(alpha, true, alphaPost.post);
editSiteForm.auth = epsilon.auth.unwrap();
await epsilon.client.editSite(editSiteForm);
- // Create the main beta community, follow it
+ // Create the main alpha/beta communities
+ await createCommunity(alpha, "main");
await createCommunity(beta, "main");
- await followBeta(beta);
}
export async function createPost(
API,
resolveComment,
saveUserSettingsFederated,
+ setupLogins,
} from './shared';
+beforeAll(async () => {
+ await setupLogins();
+});
+
let apShortname: string;
function assertUserFederation(userOne: PersonViewSafe, userTwo: PersonViewSafe) {
site::{ResolveObject, ResolveObjectResponse},
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
-use lemmy_apub::fetcher::search::{search_by_apub_id, SearchableObjects};
+use lemmy_apub::fetcher::search::{search_query_to_object_id, SearchableObjects};
use lemmy_db_schema::{newtypes::PersonId, utils::DbPool};
use lemmy_db_views::structs::{CommentView, PostView};
use lemmy_db_views_actor::structs::{CommunityView, PersonViewSafe};
.await?;
check_private_instance(&local_user_view, context.pool()).await?;
- let res = search_by_apub_id(&self.q, context)
+ let res = search_query_to_object_id(&self.q, local_user_view.is_none(), context)
.await
.map_err(|e| e.with_message("couldnt_find_object"))?;
convert_response(res, local_user_view.map(|l| l.person.id), context.pool())
Ok(actor?)
} else {
// Fetch the actor from its home instance using webfinger
- let id = webfinger_resolve_actor::<Actor>(identifier, context, &mut 0).await?;
+ let id = webfinger_resolve_actor::<Actor>(identifier, true, context, &mut 0).await?;
let actor: DbActor = blocking(context.pool(), move |conn| {
DbActor::read_from_apub_id(conn, &id)
})
use serde::Deserialize;
use url::Url;
-/// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
-///
-/// Some working examples for use with the `docker/federation/` setup:
-/// http://lemmy_alpha:8541/c/main, or !main@lemmy_alpha:8541
-/// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551
-/// http://lemmy_gamma:8561/post/3
-/// http://lemmy_delta:8571/comment/2
+/// Converts search query to object id. The query can either be an URL, which will be treated as
+/// ObjectId directly, or a webfinger identifier (@user@example.com or !community@example.com)
+/// which gets resolved to an URL.
#[tracing::instrument(skip_all)]
-pub async fn search_by_apub_id(
+pub async fn search_query_to_object_id(
query: &str,
+ local_only: bool,
context: &LemmyContext,
) -> Result<SearchableObjects, LemmyError> {
let request_counter = &mut 0;
- let instance = local_instance(context);
- match Url::parse(query) {
- Ok(url) => {
- ObjectId::new(url)
- .dereference(context, instance, request_counter)
- .await
- }
+ let object_id = match Url::parse(query) {
+ // its already an url, just go with it
+ Ok(url) => ObjectId::new(url),
Err(_) => {
+ // not an url, try to resolve via webfinger
let mut chars = query.chars();
let kind = chars.next();
let identifier = chars.as_str();
- match kind {
+ let id = match kind {
Some('@') => {
- let id =
- webfinger_resolve_actor::<ApubPerson>(identifier, context, request_counter).await?;
- Ok(SearchableObjects::Person(
- ObjectId::new(id)
- .dereference(context, instance, request_counter)
- .await?,
- ))
+ webfinger_resolve_actor::<ApubPerson>(identifier, local_only, context, request_counter)
+ .await?
}
Some('!') => {
- let id =
- webfinger_resolve_actor::<ApubCommunity>(identifier, context, request_counter).await?;
- Ok(SearchableObjects::Community(
- ObjectId::new(id)
- .dereference(context, instance, request_counter)
- .await?,
- ))
+ webfinger_resolve_actor::<ApubCommunity>(identifier, local_only, context, request_counter)
+ .await?
}
- _ => Err(LemmyError::from_message("invalid query")),
- }
+ _ => return Err(LemmyError::from_message("invalid query")),
+ };
+ ObjectId::new(id)
}
+ };
+ if local_only {
+ object_id.dereference_local(context).await
+ } else {
+ object_id
+ .dereference(context, local_instance(context), request_counter)
+ .await
}
}
#[tracing::instrument(skip_all)]
pub(crate) async fn webfinger_resolve_actor<Kind>(
identifier: &str,
+ local_only: bool,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<DbUrl, LemmyError>
.filter_map(|l| l.href.clone())
.collect();
for l in links {
- let object = ObjectId::<Kind>::new(l)
- .dereference(context, local_instance(context), request_counter)
- .await;
+ let object_id = ObjectId::<Kind>::new(l);
+ let object = if local_only {
+ object_id.dereference_local(context).await
+ } else {
+ object_id
+ .dereference(context, local_instance(context), request_counter)
+ .await
+ };
if object.is_ok() {
return object.map(|o| o.actor_id().into());
}
.collect::<Vec<MentionData>>();
for mention in &mentions {
- // TODO should it be fetching it every time?
let identifier = format!("{}@{}", mention.name, mention.domain);
let actor_id =
- webfinger_resolve_actor::<ApubPerson>(&identifier, context, request_counter).await;
+ webfinger_resolve_actor::<ApubPerson>(&identifier, true, context, request_counter).await;
if let Ok(actor_id) = actor_id {
let actor_id: ObjectId<ApubPerson> = ObjectId::new(actor_id);
addressed_ccs.push(actor_id.to_string().parse()?);