mirror of
https://github.com/LemmyNet/lemmy.git
synced 2026-04-27 03:42:45 -05:00
bc23e95f50
* Implement multi-community (fixes #818, fixes #5340) * db methods * add api methods * ts opt * wip * sql queries * cleanup * wip: federation * query by name * add ap_id column * add read_apub, compiles now * validate multi-comm name * disallow removed, deleted, private * scheduled task * remove piefed test * resolve_object with workaround * review * avoid db read * api client * fix api test fetch * wip: test cases * wip * add max elements, array_remove comments * simplify post view query * mvoe structs * fix api test * fix api test * rename to suggested_communities, add api param * filter removed/deleted * check_api_elements_count * filter out removed/deleted during update * inner join * add listing type suggested * db schema changes * transaction * address some review comments * separate methods for create, delete entry * update js client * get multi * remove CommunityOrMulti * check helper, other stuff * fix api test * change get multi comm return type * Replace MultiCommunityView with GetMultiCommunityResponse * get rid of todo * add local column, admins can edit local multi-comm * implement multi-comm follow (db and api) * api for multi-comm follow * move and rename MultiCommunityApub * move multi-comm to apub-objects * move multi-comm url to top-level * list multi-comms followed by user * add todo * remove param * update local follows * update query * db functions and tests * cleanup * fix api test * add entry limit * rewrite links * federation changes * wip federation * simplify generate_activity_id * more wip * more wip * multi-comm follow * federate changes * cleanup * clippy * test fixes * fmt * fix * wip: update follows after federated multi-comm change * remove scheduled task * update follows after multi update * fmt * fixes * review comments * indexes * remove MultiCommunityApub * fix test * ts fix * review * db schema for local_site.multi_comm_follower * adjust code and tests * fixes * cleanup, comment * fix tests * fix * remove more test code * fix new install * add index * fix api tests * fix * remove index * more fix * Implement multi-community search (fixes #5778) (#5779) * Implement multi-community search (fixes #5778) * fixes * search title and description * MultiCommunityView * rename fields * revert test change
355 lines
11 KiB
TypeScript
355 lines
11 KiB
TypeScript
jest.setTimeout(120000);
|
|
|
|
import {
|
|
UploadImage,
|
|
PurgePerson,
|
|
PurgePost,
|
|
DeleteImageParams,
|
|
} from "lemmy-js-client";
|
|
import {
|
|
alpha,
|
|
alphaImage,
|
|
alphaUrl,
|
|
beta,
|
|
betaUrl,
|
|
createCommunity,
|
|
createPost,
|
|
deleteAllMedia,
|
|
epsilon,
|
|
followCommunity,
|
|
gamma,
|
|
imageFetchLimit,
|
|
registerUser,
|
|
resolveBetaCommunity,
|
|
resolveCommunity,
|
|
resolvePost,
|
|
setupLogins,
|
|
waitForPost,
|
|
unfollows,
|
|
getPost,
|
|
waitUntil,
|
|
createPostWithThumbnail,
|
|
sampleImage,
|
|
sampleSite,
|
|
getMyUser,
|
|
} from "./shared";
|
|
|
|
beforeAll(setupLogins);
|
|
|
|
afterAll(async () => {
|
|
await Promise.allSettled([unfollows(), deleteAllMedia(alpha)]);
|
|
});
|
|
|
|
test("Upload image and delete it", async () => {
|
|
const health = await alpha.imageHealth();
|
|
expect(health.success).toBeTruthy();
|
|
|
|
// Upload test image. We use a simple string buffer as pictrs doesn't require an actual image
|
|
// in testing mode.
|
|
const upload_form: UploadImage = {
|
|
image: Buffer.from("test"),
|
|
};
|
|
const upload = await alphaImage.uploadImage(upload_form);
|
|
expect(upload.image_url).toBeDefined();
|
|
expect(upload.filename).toBeDefined();
|
|
|
|
// ensure that image download is working. theres probably a better way to do this
|
|
const response = await fetch(upload.image_url ?? "");
|
|
const content = await response.text();
|
|
expect(content.length).toBeGreaterThan(0);
|
|
|
|
// Ensure that it comes back with the list_media endpoint
|
|
const listMediaRes = await alphaImage.listMedia();
|
|
expect(listMediaRes.images.length).toBe(1);
|
|
|
|
// Ensure that it also comes back with the admin all images
|
|
const listMediaAdminRes = await alpha.listMediaAdmin({
|
|
limit: imageFetchLimit,
|
|
});
|
|
|
|
// This number comes from all the previous thumbnails fetched in other tests.
|
|
const previousThumbnails = 1;
|
|
expect(listMediaAdminRes.images.length).toBe(previousThumbnails);
|
|
|
|
// Make sure the uploader is correct
|
|
expect(listMediaRes.images[0].person.ap_id).toBe(
|
|
`http://lemmy-alpha:8541/u/lemmy_alpha`,
|
|
);
|
|
|
|
// delete image
|
|
const delete_form: DeleteImageParams = {
|
|
filename: upload.filename,
|
|
};
|
|
const delete_ = await alphaImage.deleteMedia(delete_form);
|
|
expect(delete_.success).toBe(true);
|
|
|
|
// ensure that image is deleted
|
|
const response2 = await fetch(upload.image_url ?? "");
|
|
const content2 = await response2.text();
|
|
expect(content2).toBe("");
|
|
|
|
// Ensure that it shows the image is deleted
|
|
const deletedListMediaRes = await alphaImage.listMedia();
|
|
expect(deletedListMediaRes.images.length).toBe(0);
|
|
|
|
// Ensure that the admin shows its deleted
|
|
const deletedListAllMediaRes = await alphaImage.listMediaAdmin({
|
|
limit: imageFetchLimit,
|
|
});
|
|
expect(deletedListAllMediaRes.images.length).toBe(previousThumbnails - 1);
|
|
});
|
|
|
|
test("Purge user, uploaded image removed", async () => {
|
|
let user = await registerUser(alphaImage, alphaUrl);
|
|
|
|
// upload test image
|
|
const upload_form: UploadImage = {
|
|
image: Buffer.from("test"),
|
|
};
|
|
const upload = await user.uploadImage(upload_form);
|
|
expect(upload.filename).toBeDefined();
|
|
expect(upload.image_url).toBeDefined();
|
|
|
|
// ensure that image download is working. theres probably a better way to do this
|
|
const response = await fetch(upload.image_url ?? "");
|
|
const content = await response.text();
|
|
expect(content.length).toBeGreaterThan(0);
|
|
|
|
// purge user
|
|
let my_user = await getMyUser(user);
|
|
const purgeForm: PurgePerson = {
|
|
person_id: my_user.local_user_view.person.id,
|
|
};
|
|
const delete_ = await alphaImage.purgePerson(purgeForm);
|
|
expect(delete_.success).toBe(true);
|
|
|
|
// ensure that image is deleted
|
|
const response2 = await fetch(upload.image_url ?? "");
|
|
const content2 = await response2.text();
|
|
expect(content2).toBe("");
|
|
});
|
|
|
|
test("Purge post, linked image removed", async () => {
|
|
let user = await registerUser(beta, betaUrl);
|
|
|
|
// upload test image
|
|
const upload_form: UploadImage = {
|
|
image: Buffer.from("test"),
|
|
};
|
|
const upload = await user.uploadImage(upload_form);
|
|
expect(upload.filename).toBeDefined();
|
|
expect(upload.image_url).toBeDefined();
|
|
|
|
// ensure that image download is working. theres probably a better way to do this
|
|
const response = await fetch(upload.image_url ?? "");
|
|
const content = await response.text();
|
|
expect(content.length).toBeGreaterThan(0);
|
|
|
|
let community = await resolveBetaCommunity(user);
|
|
let post = await createPost(user, community!.community.id, upload.image_url);
|
|
expect(post.post_view.post.url).toBe(upload.image_url);
|
|
expect(post.post_view.image_details).toBeDefined();
|
|
|
|
// purge post
|
|
const purgeForm: PurgePost = {
|
|
post_id: post.post_view.post.id,
|
|
};
|
|
const delete_ = await beta.purgePost(purgeForm);
|
|
expect(delete_.success).toBe(true);
|
|
|
|
// ensure that image is deleted
|
|
const response2 = await fetch(upload.image_url ?? "");
|
|
const content2 = await response2.text();
|
|
expect(content2).toBe("");
|
|
});
|
|
|
|
test("Images in remote image post are proxied if setting enabled", async () => {
|
|
let community = await createCommunity(gamma);
|
|
let postRes = await createPost(
|
|
gamma,
|
|
community.community_view.community.id,
|
|
sampleImage,
|
|
``,
|
|
);
|
|
const post = postRes.post_view.post;
|
|
expect(post).toBeDefined();
|
|
|
|
// Make sure it fetched the image details
|
|
expect(postRes.post_view.image_details).toBeDefined();
|
|
|
|
// remote image gets proxied after upload
|
|
expect(
|
|
post.thumbnail_url?.startsWith(
|
|
"http://lemmy-gamma:8561/api/v4/image/proxy?url",
|
|
),
|
|
).toBeTruthy();
|
|
expect(
|
|
post.body?.startsWith(",
|
|
).toBeTruthy();
|
|
|
|
// Make sure that it contains `jpg`, to be sure its an image
|
|
expect(post.thumbnail_url?.includes(".jpg")).toBeTruthy();
|
|
|
|
let epsilonPostRes = await resolvePost(epsilon, postRes.post_view.post);
|
|
expect(epsilonPostRes?.post).toBeDefined();
|
|
|
|
// Fetch the post again, the metadata should be backgrounded now
|
|
// Wait for the metadata to get fetched, since this is backgrounded now
|
|
let epsilonPostRes2 = await waitUntil(
|
|
() => getPost(epsilon, epsilonPostRes!.post.id),
|
|
p => p.post_view.post.thumbnail_url != undefined,
|
|
);
|
|
const epsilonPost = epsilonPostRes2.post_view.post;
|
|
|
|
expect(
|
|
epsilonPost.thumbnail_url?.startsWith(
|
|
"http://lemmy-epsilon:8581/api/v4/image/proxy?url",
|
|
),
|
|
).toBeTruthy();
|
|
expect(
|
|
epsilonPost.body?.startsWith(
|
|
",
|
|
).toBeTruthy();
|
|
|
|
// Make sure that it contains `jpg`, to be sure its an image
|
|
expect(epsilonPost.thumbnail_url?.includes(".jpg")).toBeTruthy();
|
|
});
|
|
|
|
test("Thumbnail of remote image link is proxied if setting enabled", async () => {
|
|
let community = await createCommunity(gamma);
|
|
let postRes = await createPost(
|
|
gamma,
|
|
community.community_view.community.id,
|
|
// The sample site metadata thumbnail ends in png
|
|
sampleSite,
|
|
);
|
|
const post = postRes.post_view.post;
|
|
expect(post).toBeDefined();
|
|
|
|
// remote image gets proxied after upload
|
|
expect(
|
|
post.thumbnail_url?.startsWith(
|
|
"http://lemmy-gamma:8561/api/v4/image/proxy?url",
|
|
),
|
|
).toBeTruthy();
|
|
|
|
// Make sure that it contains `png`, to be sure its an image
|
|
expect(post.thumbnail_url?.includes(".png")).toBeTruthy();
|
|
|
|
let epsilonPostRes = await resolvePost(epsilon, postRes.post_view.post);
|
|
expect(epsilonPostRes?.post).toBeDefined();
|
|
|
|
let epsilonPostRes2 = await waitUntil(
|
|
() => getPost(epsilon, epsilonPostRes!.post.id),
|
|
p => p.post_view.post.thumbnail_url != undefined,
|
|
);
|
|
const epsilonPost = epsilonPostRes2.post_view.post;
|
|
|
|
expect(
|
|
epsilonPost.thumbnail_url?.startsWith(
|
|
"http://lemmy-epsilon:8581/api/v4/image/proxy?url",
|
|
),
|
|
).toBeTruthy();
|
|
|
|
// Make sure that it contains `png`, to be sure its an image
|
|
expect(epsilonPost.thumbnail_url?.includes(".png")).toBeTruthy();
|
|
});
|
|
|
|
test("No image proxying if setting is disabled", async () => {
|
|
let user = await registerUser(beta, betaUrl);
|
|
let community = await createCommunity(alpha);
|
|
let betaCommunity = await resolveCommunity(
|
|
beta,
|
|
community.community_view.community.ap_id,
|
|
);
|
|
await followCommunity(beta, true, betaCommunity!.community.id);
|
|
|
|
const upload_form: UploadImage = {
|
|
image: Buffer.from("test"),
|
|
};
|
|
const upload = await user.uploadImage(upload_form);
|
|
let post = await createPost(
|
|
alpha,
|
|
community.community_view.community.id,
|
|
upload.image_url,
|
|
``,
|
|
);
|
|
expect(post.post_view.post).toBeDefined();
|
|
|
|
// remote image doesn't get proxied after upload
|
|
expect(
|
|
post.post_view.post.url?.startsWith("http://lemmy-beta:8551/api/v4/image/"),
|
|
).toBeTruthy();
|
|
expect(post.post_view.post.body).toBe(``);
|
|
|
|
let betaPost = await waitForPost(beta, post.post_view.post, res => {
|
|
return res?.post.alt_text != null;
|
|
});
|
|
expect(betaPost.post).toBeDefined();
|
|
|
|
// remote image doesn't get proxied after federation
|
|
expect(
|
|
betaPost.post.url?.startsWith("http://lemmy-beta:8551/api/v4/image/"),
|
|
).toBeTruthy();
|
|
expect(betaPost.post.body).toBe(``);
|
|
// Make sure the alt text got federated
|
|
expect(post.post_view.post.alt_text).toBe(betaPost.post.alt_text);
|
|
});
|
|
|
|
test("Make regular post, and give it a custom thumbnail", async () => {
|
|
const uploadForm1: UploadImage = {
|
|
image: Buffer.from("testRegular1"),
|
|
};
|
|
const upload1 = await alphaImage.uploadImage(uploadForm1);
|
|
|
|
const community = await createCommunity(alphaImage);
|
|
|
|
// Use wikipedia since it has an opengraph image
|
|
const wikipediaUrl = "https://wikipedia.org/";
|
|
|
|
let post = await createPostWithThumbnail(
|
|
alphaImage,
|
|
community.community_view.community.id,
|
|
wikipediaUrl,
|
|
upload1.image_url!,
|
|
);
|
|
|
|
// Wait for the metadata to get fetched, since this is backgrounded now
|
|
post = await waitUntil(
|
|
() => getPost(alphaImage, post.post_view.post.id),
|
|
p => p.post_view.post.thumbnail_url != undefined,
|
|
);
|
|
expect(post.post_view.post.url).toBe(wikipediaUrl);
|
|
// Make sure it uses custom thumbnail
|
|
expect(post.post_view.post.thumbnail_url).toBe(upload1.image_url);
|
|
});
|
|
|
|
test("Create an image post, and make sure a custom thumbnail doesn't overwrite it", async () => {
|
|
const uploadForm1: UploadImage = {
|
|
image: Buffer.from("test1"),
|
|
};
|
|
const upload1 = await alphaImage.uploadImage(uploadForm1);
|
|
|
|
const uploadForm2: UploadImage = {
|
|
image: Buffer.from("test2"),
|
|
};
|
|
const upload2 = await alphaImage.uploadImage(uploadForm2);
|
|
|
|
const community = await createCommunity(alphaImage);
|
|
|
|
let post = await createPostWithThumbnail(
|
|
alphaImage,
|
|
community.community_view.community.id,
|
|
upload1.image_url!,
|
|
upload2.image_url!,
|
|
);
|
|
post = await waitUntil(
|
|
() => getPost(alphaImage, post.post_view.post.id),
|
|
p => p.post_view.post.thumbnail_url != undefined,
|
|
);
|
|
expect(post.post_view.post.url).toBe(upload1.image_url);
|
|
// Make sure the custom thumbnail is ignored
|
|
expect(post.post_view.post.thumbnail_url == upload2.image_url).toBe(false);
|
|
});
|