implement ActivitySender actor #89

Merged
dessalines merged 28 commits from activity-sender into main 2020-08-31 13:48:03 +00:00
9 changed files with 111 additions and 16 deletions
Showing only changes of commit 4db6585da0 - Show all commits

View File

@ -164,17 +164,13 @@ impl Comment {
}
pub fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
println!("Comment::upsert() (entered into function)");
let existing = Self::read_from_apub_id(conn, &comment_form.ap_id.as_ref().unwrap());
println!("Comment::upsert() (checked if comment exists)");
let x = match existing {
Err(NotFound {}) => Ok(Self::create(conn, &comment_form)?),
// both the old and new comment should be identical so no need to do an update here
Ok(p) => Ok(Self::read(conn, p.id)?),
Err(e) => Err(e),
};
println!("Comment::upsert() (after match statement)");
x
use crate::schema::comment::dsl::*;
insert_into(comment)
.values(comment_form)
.on_conflict(ap_id)
.do_update()
.set(comment_form)
.get_result::<Self>(conn)
}
}

View File

@ -183,7 +183,9 @@ impl Post {
use crate::schema::post::dsl::*;
insert_into(post)
.values(post_form)
.on_conflict_do_nothing()
.on_conflict(ap_id)
.do_update()
.set(post_form)
.get_result::<Self>(conn)
}
}

View File

@ -119,6 +119,17 @@ impl PrivateMessage {
.set(read.eq(true))
.get_results::<Self>(conn)
}
// TODO use this
pub fn upsert(conn: &PgConnection, private_message_form: &PrivateMessageForm) -> Result<Self, Error> {
use crate::schema::private_message::dsl::*;
insert_into(private_message)
.values(private_message_form)
.on_conflict(ap_id)
.do_update()
.set(private_message_form)
.get_result::<Self>(conn)
}
}
#[cfg(test)]

View File

@ -19,6 +19,7 @@ import {
createCommunity,
registerUser,
API,
delay,
} from './shared';
import { PostResponse } from 'lemmy-js-client';
@ -47,6 +48,7 @@ test('Create a comment', async () => {
expect(commentRes.comment.community_local).toBe(false);
expect(commentRes.comment.creator_local).toBe(true);
expect(commentRes.comment.score).toBe(1);
await delay(5000);
// Make sure that comment is liked on beta
let searchBeta = await searchComment(beta, commentRes.comment);
@ -64,6 +66,7 @@ test('Create a comment in a non-existent post', async () => {
test('Update a comment', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let updateCommentRes = await updateComment(alpha, commentRes.comment.id);
expect(updateCommentRes.comment.content).toBe(
'A jest test federated comment update'
@ -79,12 +82,15 @@ test('Update a comment', async () => {
test('Delete a comment', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let deleteCommentRes = await deleteComment(
alpha,
true,
commentRes.comment.id
);
expect(deleteCommentRes.comment.deleted).toBe(true);
await delay();
// Make sure that comment is deleted on beta
// The search doesnt work below, because it returns a tombstone / http::gone
@ -93,6 +99,7 @@ test('Delete a comment', async () => {
// let betaComment = searchBeta.comments[0];
// Create a fake post, just to get the previous new post id
let createdBetaPostJustToGetId = await createPost(beta, 2);
await delay();
let betaPost = await getPost(beta, createdBetaPostJustToGetId.post.id - 1);
let betaComment = betaPost.comments[0];
expect(betaComment.deleted).toBe(true);
@ -103,6 +110,7 @@ test('Delete a comment', async () => {
commentRes.comment.id
);
expect(undeleteCommentRes.comment.deleted).toBe(false);
await delay();
// Make sure that comment is undeleted on beta
let searchBeta2 = await searchComment(beta, commentRes.comment);
@ -112,6 +120,7 @@ test('Delete a comment', async () => {
test('Remove a comment from admin and community on the same instance', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
// Get the id for beta
let betaCommentId = (await searchComment(beta, commentRes.comment))
@ -120,6 +129,7 @@ test('Remove a comment from admin and community on the same instance', async ()
// The beta admin removes it (the community lives on beta)
let removeCommentRes = await removeComment(beta, true, betaCommentId);
expect(removeCommentRes.comment.removed).toBe(true);
await delay();
// Make sure that comment is removed on alpha (it gets pushed since an admin from beta removed it)
let refetchedPost = await getPost(alpha, postRes.post.id);
@ -127,6 +137,7 @@ test('Remove a comment from admin and community on the same instance', async ()
let unremoveCommentRes = await removeComment(beta, false, betaCommentId);
expect(unremoveCommentRes.comment.removed).toBe(false);
await delay();
// Make sure that comment is unremoved on beta
let refetchedPost2 = await getPost(alpha, postRes.post.id);
@ -142,15 +153,19 @@ test('Remove a comment from admin and community on different instance', async ()
// New alpha user creates a community, post, and comment.
let newCommunity = await createCommunity(newAlphaApi);
await delay();
let newPost = await createPost(newAlphaApi, newCommunity.community.id);
await delay();
let commentRes = await createComment(newAlphaApi, newPost.post.id);
expect(commentRes.comment.content).toBeDefined();
await delay();
// Beta searches that to cache it, then removes it
let searchBeta = await searchComment(beta, commentRes.comment);
let betaComment = searchBeta.comments[0];
let removeCommentRes = await removeComment(beta, true, betaComment.id);
expect(removeCommentRes.comment.removed).toBe(true);
await delay();
// Make sure its not removed on alpha
let refetchedPost = await getPost(newAlphaApi, newPost.post.id);
@ -159,8 +174,10 @@ test('Remove a comment from admin and community on different instance', async ()
test('Unlike a comment', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let unlike = await likeComment(alpha, 0, commentRes.comment);
expect(unlike.comment.score).toBe(0);
await delay();
// Make sure that post is unliked on beta
let searchBeta = await searchComment(beta, commentRes.comment);
@ -173,6 +190,7 @@ test('Unlike a comment', async () => {
test('Federated comment like', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
// Find the comment on beta
let searchBeta = await searchComment(beta, commentRes.comment);
@ -180,6 +198,7 @@ test('Federated comment like', async () => {
let like = await likeComment(beta, 1, betaComment);
expect(like.comment.score).toBe(2);
await delay();
// Get the post from alpha, check the likes
let post = await getPost(alpha, postRes.post.id);
@ -189,6 +208,7 @@ test('Federated comment like', async () => {
test('Reply to a comment', async () => {
// Create a comment on alpha, find it on beta
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let searchBeta = await searchComment(beta, commentRes.comment);
let betaComment = searchBeta.comments[0];
@ -201,6 +221,7 @@ test('Reply to a comment', async () => {
expect(replyRes.comment.creator_local).toBe(true);
expect(replyRes.comment.parent_id).toBe(betaComment.id);
expect(replyRes.comment.score).toBe(1);
await delay();
// Make sure that comment is seen on alpha
// TODO not sure why, but a searchComment back to alpha, for the ap_id of betas
@ -219,6 +240,7 @@ test('Mention beta', async () => {
// Create a mention on alpha
let mentionContent = 'A test mention of @lemmy_beta@lemmy-beta:8550';
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let mentionRes = await createComment(
alpha,
postRes.post.id,
@ -229,6 +251,7 @@ test('Mention beta', async () => {
expect(mentionRes.comment.community_local).toBe(false);
expect(mentionRes.comment.creator_local).toBe(true);
expect(mentionRes.comment.score).toBe(1);
await delay();
let mentionsRes = await getMentions(beta);
expect(mentionsRes.mentions[0].content).toBeDefined();
@ -239,6 +262,7 @@ test('Mention beta', async () => {
test('Comment Search', async () => {
let commentRes = await createComment(alpha, postRes.post.id);
await delay();
let searchBeta = await searchComment(beta, commentRes.comment);
expect(searchBeta.comments[0].ap_id).toBe(commentRes.comment.ap_id);
});
@ -247,6 +271,7 @@ test('A and G subscribe to B (center) A posts, G mentions B, it gets announced t
// Create a local post
let alphaPost = await createPost(alpha, 2);
expect(alphaPost.post.community_local).toBe(true);
await delay();
// Make sure gamma sees it
let search = await searchPost(gamma, alphaPost.post);
@ -264,6 +289,7 @@ test('A and G subscribe to B (center) A posts, G mentions B, it gets announced t
expect(commentRes.comment.community_local).toBe(false);
expect(commentRes.comment.creator_local).toBe(true);
expect(commentRes.comment.score).toBe(1);
await delay();
// Make sure alpha sees it
let alphaPost2 = await getPost(alpha, alphaPost.post.id);
@ -291,6 +317,7 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde
// B creates a post, and two comments, should be invisible to A
let postRes = await createPost(beta, 2);
expect(postRes.post.name).toBeDefined();
await delay();
let parentCommentContent = 'An invisible top level comment from beta';
let parentCommentRes = await createComment(
@ -300,6 +327,7 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde
parentCommentContent
);
expect(parentCommentRes.comment.content).toBe(parentCommentContent);
await delay();
// B creates a comment, then a child one of that.
let childCommentContent = 'An invisible child comment from beta';
@ -310,11 +338,13 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde
childCommentContent
);
expect(childCommentRes.comment.content).toBe(childCommentContent);
await delay();
// Follow beta again
let follow = await followBeta(alpha);
expect(follow.community.local).toBe(false);
expect(follow.community.name).toBe('main');
await delay();
// An update to the child comment on beta, should push the post, parent, and child to alpha now
let updatedCommentContent = 'An update child comment from beta';
@ -324,9 +354,11 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde
updatedCommentContent
);
expect(updateRes.comment.content).toBe(updatedCommentContent);
await delay();
// Get the post from alpha
let createFakeAlphaPostToGetId = await createPost(alpha, 2);
await delay();
let alphaPost = await getPost(alpha, createFakeAlphaPostToGetId.post.id - 1);
expect(alphaPost.post.name).toBeDefined();
expect(alphaPost.comments[1].content).toBe(parentCommentContent);

View File

@ -6,6 +6,7 @@ import {
createCommunity,
deleteCommunity,
removeCommunity,
delay,
} from './shared';
beforeAll(async () => {
@ -24,12 +25,14 @@ test('Create community', async () => {
test('Delete community', async () => {
let communityRes = await createCommunity(beta);
await delay();
let deleteCommunityRes = await deleteCommunity(
beta,
true,
communityRes.community.id
);
expect(deleteCommunityRes.community.deleted).toBe(true);
await delay();
// Make sure it got deleted on A
let search = await searchForBetaCommunity(alpha);
@ -44,6 +47,7 @@ test('Delete community', async () => {
communityRes.community.id
);
expect(undeleteCommunityRes.community.deleted).toBe(false);
await delay();
// Make sure it got undeleted on A
let search2 = await searchForBetaCommunity(alpha);
@ -54,6 +58,7 @@ test('Delete community', async () => {
test('Remove community', async () => {
let communityRes = await createCommunity(beta);
await delay();
let removeCommunityRes = await removeCommunity(
beta,
true,
@ -74,6 +79,7 @@ test('Remove community', async () => {
communityRes.community.id
);
expect(unremoveCommunityRes.community.removed).toBe(false);
await delay();
// Make sure it got unremoved on A
let search2 = await searchForBetaCommunity(alpha);

View File

@ -5,6 +5,7 @@ import {
followCommunity,
checkFollowedCommunities,
unfollowRemotes,
delay,
} from './shared';
beforeAll(async () => {
@ -22,6 +23,7 @@ test('Follow federated community', async () => {
// Make sure the follow response went through
expect(follow.community.local).toBe(false);
expect(follow.community.name).toBe('main');
await delay();
// Check it from local
let followCheck = await checkFollowedCommunities(alpha);
@ -33,6 +35,7 @@ test('Follow federated community', async () => {
// Test an unfollow
let unfollow = await followCommunity(alpha, false, remoteCommunityId);
expect(unfollow.community.local).toBe(false);
await delay();
// Make sure you are unsubbed locally
let unfollowCheck = await checkFollowedCommunities(alpha);

View File

@ -18,6 +18,7 @@ import {
removePost,
getPost,
unfollowRemotes,
delay,
} from './shared';
beforeAll(async () => {
@ -37,11 +38,13 @@ afterAll(async () => {
test('Create a post', async () => {
let search = await searchForBetaCommunity(alpha);
await delay();
let postRes = await createPost(alpha, search.communities[0].id);
expect(postRes.post).toBeDefined();
expect(postRes.post.community_local).toBe(false);
expect(postRes.post.creator_local).toBe(true);
expect(postRes.post.score).toBe(1);
await delay(5000);
// Make sure that post is liked on beta
let searchBeta = await searchPost(beta, postRes.post);
@ -69,12 +72,15 @@ test('Create a post in a non-existent community', async () => {
test('Unlike a post', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let unlike = await likePost(alpha, 0, postRes.post);
expect(unlike.post.score).toBe(0);
await delay();
// Try to unlike it again, make sure it stays at 0
let unlike2 = await likePost(alpha, 0, postRes.post);
expect(unlike2.post.score).toBe(0);
await delay();
// Make sure that post is unliked on beta
let searchBeta = await searchPost(beta, postRes.post);
@ -89,12 +95,14 @@ test('Unlike a post', async () => {
test('Update a post', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let updatedName = 'A jest test federated post, updated';
let updatedPost = await updatePost(alpha, postRes.post);
expect(updatedPost.post.name).toBe(updatedName);
expect(updatedPost.post.community_local).toBe(false);
expect(updatedPost.post.creator_local).toBe(true);
await delay();
// Make sure that post is updated on beta
let searchBeta = await searchPost(beta, postRes.post);
@ -102,6 +110,7 @@ test('Update a post', async () => {
expect(betaPost.community_local).toBe(true);
expect(betaPost.creator_local).toBe(false);
expect(betaPost.name).toBe(updatedName);
await delay();
// Make sure lemmy beta cannot update the post
let updatedPostBeta = await updatePost(beta, betaPost);
@ -111,9 +120,11 @@ test('Update a post', async () => {
test('Sticky a post', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let stickiedPostRes = await stickyPost(alpha, true, postRes.post);
expect(stickiedPostRes.post.stickied).toBe(true);
await delay();
// Make sure that post is stickied on beta
let searchBeta = await searchPost(beta, postRes.post);
@ -125,6 +136,7 @@ test('Sticky a post', async () => {
// Unsticky a post
let unstickiedPost = await stickyPost(alpha, false, postRes.post);
expect(unstickiedPost.post.stickied).toBe(false);
await delay();
// Make sure that post is unstickied on beta
let searchBeta2 = await searchPost(beta, postRes.post);
@ -137,6 +149,7 @@ test('Sticky a post', async () => {
let searchGamma = await searchPost(gamma, postRes.post);
let gammaPost = searchGamma.posts[0];
let gammaTrySticky = await stickyPost(gamma, true, gammaPost);
await delay();
let searchBeta3 = await searchPost(beta, postRes.post);
let betaPost3 = searchBeta3.posts[0];
expect(gammaTrySticky.post.stickied).toBe(true);
@ -145,10 +158,13 @@ test('Sticky a post', async () => {
test('Lock a post', async () => {
let search = await searchForBetaCommunity(alpha);
await delay();
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let lockedPostRes = await lockPost(alpha, true, postRes.post);
expect(lockedPostRes.post.locked).toBe(true);
await delay();
// Make sure that post is locked on beta
let searchBeta = await searchPost(beta, postRes.post);
@ -160,14 +176,17 @@ test('Lock a post', async () => {
// Try to make a new comment there, on alpha
let comment = await createComment(alpha, postRes.post.id);
expect(comment['error']).toBe('locked');
await delay();
// Try to create a new comment, on beta
let commentBeta = await createComment(beta, betaPost.id);
expect(commentBeta['error']).toBe('locked');
await delay();
// Unlock a post
let unlockedPost = await lockPost(alpha, false, postRes.post);
expect(unlockedPost.post.locked).toBe(false);
await delay();
// Make sure that post is unlocked on beta
let searchBeta2 = await searchPost(beta, postRes.post);
@ -180,18 +199,22 @@ test('Lock a post', async () => {
test('Delete a post', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let deletedPost = await deletePost(alpha, true, postRes.post);
expect(deletedPost.post.deleted).toBe(true);
await delay();
// Make sure lemmy beta sees post is deleted
let createFakeBetaPostToGetId = (await createPost(beta, 2)).post.id - 1;
await delay();
let betaPost = await getPost(beta, createFakeBetaPostToGetId);
expect(betaPost.post.deleted).toBe(true);
// Undelete
let undeletedPost = await deletePost(alpha, false, postRes.post);
expect(undeletedPost.post.deleted).toBe(false);
await delay();
// Make sure lemmy beta sees post is undeleted
let betaPost2 = await getPost(beta, createFakeBetaPostToGetId);
@ -205,18 +228,22 @@ test('Delete a post', async () => {
test('Remove a post from admin and community on different instance', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let removedPost = await removePost(alpha, true, postRes.post);
expect(removedPost.post.removed).toBe(true);
await delay();
// Make sure lemmy beta sees post is NOT removed
let createFakeBetaPostToGetId = (await createPost(beta, 2)).post.id - 1;
await delay();
let betaPost = await getPost(beta, createFakeBetaPostToGetId);
expect(betaPost.post.removed).toBe(false);
// Undelete
let undeletedPost = await removePost(alpha, false, postRes.post);
expect(undeletedPost.post.removed).toBe(false);
await delay();
// Make sure lemmy beta sees post is undeleted
let betaPost2 = await getPost(beta, createFakeBetaPostToGetId);
@ -226,14 +253,17 @@ test('Remove a post from admin and community on different instance', async () =>
test('Remove a post from admin and community on same instance', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
// Get the id for beta
let createFakeBetaPostToGetId = (await createPost(beta, 2)).post.id - 1;
await delay();
let betaPost = await getPost(beta, createFakeBetaPostToGetId);
// The beta admin removes it (the community lives on beta)
let removePostRes = await removePost(beta, true, betaPost.post);
expect(removePostRes.post.removed).toBe(true);
await delay();
// Make sure lemmy alpha sees post is removed
let alphaPost = await getPost(alpha, postRes.post.id);
@ -242,6 +272,7 @@ test('Remove a post from admin and community on same instance', async () => {
// Undelete
let undeletedPost = await removePost(beta, false, betaPost.post);
expect(undeletedPost.post.removed).toBe(false);
await delay();
// Make sure lemmy alpha sees post is undeleted
let alphaPost2 = await getPost(alpha, postRes.post.id);
@ -251,6 +282,7 @@ test('Remove a post from admin and community on same instance', async () => {
test('Search for a post', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let searchBeta = await searchPost(beta, postRes.post);
expect(searchBeta.posts[0].name).toBeDefined();
@ -259,6 +291,7 @@ test('Search for a post', async () => {
test('A and G subscribe to B (center) A posts, it gets announced to G', async () => {
let search = await searchForBetaCommunity(alpha);
let postRes = await createPost(alpha, search.communities[0].id);
await delay();
let search2 = await searchPost(gamma, postRes.post);
expect(search2.posts[0].name).toBeDefined();

View File

@ -8,6 +8,7 @@ import {
listPrivateMessages,
deletePrivateMessage,
unfollowRemotes,
delay,
} from './shared';
let recipient_id: number;
@ -27,6 +28,7 @@ test('Create a private message', async () => {
expect(pmRes.message.local).toBe(true);
expect(pmRes.message.creator_local).toBe(true);
expect(pmRes.message.recipient_local).toBe(false);
await delay();
let betaPms = await listPrivateMessages(beta);
expect(betaPms.messages[0].content).toBeDefined();
@ -39,7 +41,9 @@ test('Update a private message', async () => {
let updatedContent = 'A jest test federated private message edited';
let pmRes = await createPrivateMessage(alpha, recipient_id);
await delay();
let pmUpdated = await updatePrivateMessage(alpha, pmRes.message.id);
await delay();
expect(pmUpdated.message.content).toBe(updatedContent);
let betaPms = await listPrivateMessages(beta);
@ -48,9 +52,11 @@ test('Update a private message', async () => {
test('Delete a private message', async () => {
let pmRes = await createPrivateMessage(alpha, recipient_id);
await delay();
let betaPms1 = await listPrivateMessages(beta);
let deletedPmRes = await deletePrivateMessage(alpha, true, pmRes.message.id);
expect(deletedPmRes.message.deleted).toBe(true);
await delay();
// The GetPrivateMessages filters out deleted,
// even though they are in the actual database.
@ -65,6 +71,7 @@ test('Delete a private message', async () => {
pmRes.message.id
);
expect(undeletedPmRes.message.deleted).toBe(false);
await delay();
let betaPms3 = await listPrivateMessages(beta);
expect(betaPms3.messages.length).toBe(betaPms1.messages.length);

View File

@ -198,7 +198,7 @@ export async function searchPost(
): Promise<SearchResponse> {
let form: SearchForm = {
q: post.ap_id,
type_: SearchType.All,
type_: SearchType.Posts,
sort: SortType.TopAll,
};
return api.client.search(form);
@ -220,7 +220,7 @@ export async function searchComment(
): Promise<SearchResponse> {
let form: SearchForm = {
q: comment.ap_id,
type_: SearchType.All,
type_: SearchType.Comments,
sort: SortType.TopAll,
};
return api.client.search(form);
@ -233,7 +233,7 @@ export async function searchForBetaCommunity(
// Use short-hand search url
let form: SearchForm = {
q: '!main@lemmy-beta:8550',
type_: SearchType.All,
type_: SearchType.Communities,
sort: SortType.TopAll,
};
return api.client.search(form);
@ -247,7 +247,7 @@ export async function searchForUser(
// Use short-hand search url
let form: SearchForm = {
q: apShortname,
type_: SearchType.All,
type_: SearchType.Users,
sort: SortType.TopAll,
};
return api.client.search(form);
@ -524,6 +524,11 @@ export async function followBeta(api: API): Promise<CommunityResponse> {
}
}
export const delay = (millis: number = 500) =>
new Promise((resolve, _reject) => {
setTimeout(_ => resolve(), millis);
});
export function wrapper(form: any): string {
return JSON.stringify(form);
}