Comment search and apub endpoint

This commit is contained in:
Felix 2020-05-13 19:21:32 +02:00
parent b6d261bc91
commit 7e42963d0f
4 changed files with 79 additions and 3 deletions

View file

@ -1,5 +1,24 @@
use super::*; use super::*;
#[derive(Deserialize)]
pub struct CommentQuery {
comment_id: String,
}
/// Return the post json over HTTP.
pub async fn get_apub_comment(
info: Path<CommentQuery>,
db: DbPoolParam,
) -> Result<HttpResponse<Body>, Error> {
let id = info.comment_id.parse::<i32>()?;
let comment = Comment::read(&&db.get()?, id)?;
if !comment.deleted {
Ok(create_apub_response(&comment.to_apub(&db.get().unwrap())?))
} else {
Ok(create_apub_tombstone_response(&comment.to_tombstone()?))
}
}
impl ToApub for Comment { impl ToApub for Comment {
type Response = Note; type Response = Note;

View file

@ -40,6 +40,7 @@ pub enum SearchAcceptedObjects {
Person(Box<PersonExt>), Person(Box<PersonExt>),
Group(Box<GroupExt>), Group(Box<GroupExt>),
Page(Box<PageExt>), Page(Box<PageExt>),
Comment(Box<Note>),
} }
/// Attempt to parse the query as URL, and fetch an ActivityPub object from it. /// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
@ -47,7 +48,8 @@ pub enum SearchAcceptedObjects {
/// Some working examples for use with the docker/federation/ setup: /// Some working examples for use with the docker/federation/ setup:
/// http://lemmy_alpha:8540/c/main, or !main@lemmy_alpha:8540 /// http://lemmy_alpha:8540/c/main, or !main@lemmy_alpha:8540
/// http://lemmy_alpha:8540/u/lemmy_alpha, or @lemmy_alpha@lemmy_alpha:8540 /// http://lemmy_alpha:8540/u/lemmy_alpha, or @lemmy_alpha@lemmy_alpha:8540
/// http://lemmy_alpha:8540/p/3 /// http://lemmy_alpha:8540/post/3
/// http://lemmy_alpha:8540/comment/2
pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchResponse, Error> { pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchResponse, Error> {
// Parse the shorthand query url // Parse the shorthand query url
let query_url = if query.contains('@') { let query_url = if query.contains('@') {
@ -99,6 +101,20 @@ pub fn search_by_apub_id(query: &str, conn: &PgConnection) -> Result<SearchRespo
let p = upsert_post(&PostForm::from_apub(&p, conn)?, conn)?; let p = upsert_post(&PostForm::from_apub(&p, conn)?, conn)?;
response.posts = vec![PostView::read(conn, p.id, None)?]; response.posts = vec![PostView::read(conn, p.id, None)?];
} }
SearchAcceptedObjects::Comment(c) => {
let post_url = c
.object_props
.get_many_in_reply_to_xsd_any_uris()
.unwrap()
.next()
.unwrap()
.to_string();
// TODO: also fetch parent comments if any
let post = fetch_remote_object(&Url::parse(&post_url)?)?;
upsert_post(&PostForm::from_apub(&post, conn)?, conn)?;
let c = upsert_comment(&CommentForm::from_apub(&c, conn)?, conn)?;
response.comments = vec![CommentView::read(conn, c.id, None)?];
}
} }
Ok(response) Ok(response)
} }
@ -198,6 +214,15 @@ fn upsert_post(post_form: &PostForm, conn: &PgConnection) -> Result<Post, Error>
} }
} }
fn upsert_comment(comment_form: &CommentForm, conn: &PgConnection) -> Result<Comment, Error> {
let existing = Comment::read_from_apub_id(conn, &comment_form.ap_id);
match existing {
Err(NotFound {}) => Ok(Comment::create(conn, &comment_form)?),
Ok(p) => Ok(Comment::update(conn, p.id, &comment_form)?),
Err(e) => Err(Error::from(e)),
}
}
// TODO It should not be fetching data from a community outbox. // TODO It should not be fetching data from a community outbox.
// All posts, comments, comment likes, etc should be posts to our community_inbox // All posts, comments, comment likes, etc should be posts to our community_inbox
// The only data we should be periodically fetching (if it hasn't been fetched in the last day // The only data we should be periodically fetching (if it hasn't been fetched in the last day

View file

@ -1,4 +1,5 @@
use super::*; use super::*;
use crate::apub::comment::get_apub_comment;
use crate::apub::community::*; use crate::apub::community::*;
use crate::apub::community_inbox::community_inbox; use crate::apub::community_inbox::community_inbox;
use crate::apub::post::get_apub_post; use crate::apub::post::get_apub_post;
@ -28,7 +29,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
// web::get().to(get_apub_community_outbox), // web::get().to(get_apub_community_outbox),
// ) // )
.route("/u/{user_name}", web::get().to(get_apub_user_http)) .route("/u/{user_name}", web::get().to(get_apub_user_http))
.route("/post/{post_id}", web::get().to(get_apub_post)), .route("/post/{post_id}", web::get().to(get_apub_post))
.route("/comment/{comment_id}", web::get().to(get_apub_comment)),
) )
// Inboxes dont work with the header guard for some reason. // Inboxes dont work with the header guard for some reason.
.route("/c/{community_name}/inbox", web::post().to(community_inbox)) .route("/c/{community_name}/inbox", web::post().to(community_inbox))

View file

@ -68,7 +68,7 @@ describe('main', () => {
lemmyBetaAuth = resB.jwt; lemmyBetaAuth = resB.jwt;
}); });
describe('beta_fetch', () => { describe('post_search', () => {
test('Create test post on alpha and fetch it on beta', async () => { test('Create test post on alpha and fetch it on beta', async () => {
let name = 'A jest test post'; let name = 'A jest test post';
let postForm: PostForm = { let postForm: PostForm = {
@ -1107,6 +1107,36 @@ describe('main', () => {
expect(getPrivateMessagesUnDeletedRes.messages[0].deleted).toBe(false); expect(getPrivateMessagesUnDeletedRes.messages[0].deleted).toBe(false);
}); });
}); });
describe('comment_search', () => {
test('Create comment on alpha and search it', async () => {
let content = 'A jest test federated comment for search';
let commentForm: CommentForm = {
content,
post_id: 1,
auth: lemmyAlphaAuth,
};
let createResponse: CommentResponse = await fetch(
`${lemmyAlphaApiUrl}/comment`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: wrapper(commentForm),
}
).then(d => d.json());
let searchUrl = `${lemmyBetaApiUrl}/search?q=${createResponse.comment.ap_id}&type_=All&sort=TopAll`;
let searchResponse: SearchResponse = await fetch(searchUrl, {
method: 'GET',
}).then(d => d.json());
// TODO: check more fields
expect(searchResponse.comments[0].content).toBe(content);
});
});
}); });
function wrapper(form: any): string { function wrapper(form: any): string {