]> Untitled Git - lemmy.git/commitdiff
Comment search and apub endpoint
authorFelix <me@nutomic.com>
Wed, 13 May 2020 17:21:32 +0000 (19:21 +0200)
committerFelix <me@nutomic.com>
Thu, 14 May 2020 10:42:26 +0000 (12:42 +0200)
server/src/apub/comment.rs
server/src/apub/fetcher.rs
server/src/routes/federation.rs
ui/src/api_tests/api.spec.ts

index 17da45a6bca857ab409e1fcf35b429d20fb3c7ff..4c2faa21db9b7b4280a1ed4c676bf7198a823fd7 100644 (file)
@@ -1,5 +1,24 @@
 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 {
   type Response = Note;
 
index 115ef6ff9378d04522cfeafc2a72450c6796f2b9..994e75f2bbb5a6fcf09730d7d1bccba505ded2cd 100644 (file)
@@ -40,6 +40,7 @@ pub enum SearchAcceptedObjects {
   Person(Box<PersonExt>),
   Group(Box<GroupExt>),
   Page(Box<PageExt>),
+  Comment(Box<Note>),
 }
 
 /// 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:
 /// 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/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> {
   // Parse the shorthand query url
   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)?;
       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)
 }
@@ -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.
 // 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
index c1cb7408a2e92737f2f6794f13729127e29582d3..ed5c25965886a432edfecd0d1edfea7eb48384b1 100644 (file)
@@ -1,4 +1,5 @@
 use super::*;
+use crate::apub::comment::get_apub_comment;
 use crate::apub::community::*;
 use crate::apub::community_inbox::community_inbox;
 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),
           // )
           .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.
       .route("/c/{community_name}/inbox", web::post().to(community_inbox))
index 8734169ac768b9308032ef185d0669238521467e..dcfb5e628fd032d0ebf2176eebfbad89d0ebbd1a 100644 (file)
@@ -68,7 +68,7 @@ describe('main', () => {
     lemmyBetaAuth = resB.jwt;
   });
 
-  describe('beta_fetch', () => {
+  describe('post_search', () => {
     test('Create test post on alpha and fetch it on beta', async () => {
       let name = 'A jest test post';
       let postForm: PostForm = {
@@ -1107,6 +1107,36 @@ describe('main', () => {
       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 {