jest.setTimeout(120000); import { UploadImage, PurgePerson, PurgePost, DeleteImageParams, } from "lemmy-js-client"; import { alpha, alphaImage, alphaUrl, beta, betaUrl, createCommunity, createPost, deleteAllImages, 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.all([unfollows(), deleteAllImages(alpha)]); }); test("Upload image and delete it", async () => { const health = await alpha.imageHealth(); expect(health.success).toBeTruthy(); // Before running this test, you need to delete all previous images in the DB await deleteAllImages(alpha); // 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 listAllMediaRes = await alphaImage.listAllMedia({ limit: imageFetchLimit, }); // This number comes from all the previous thumbnails fetched in other tests. const previousThumbnails = 1; expect(listAllMediaRes.images.length).toBe(previousThumbnails); // Make sure the uploader is correct expect(listMediaRes.images[0].person.actor_id).toBe( `http://lemmy-alpha:8541/u/lemmy_alpha`, ); // delete image const delete_form: DeleteImageParams = { filename: upload.filename, }; const delete_ = await alphaImage.deleteImage(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.listAllMedia({ 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!.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, `![](${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("![](http://lemmy-gamma:8561/api/v4/image/proxy?url"), ).toBeTruthy(); // Make sure that it ends with jpg, to be sure its an image expect(post.thumbnail_url?.endsWith(".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!.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( "![](http://lemmy-epsilon:8581/api/v4/image/proxy?url", ), ).toBeTruthy(); // Make sure that it ends with jpg, to be sure its an image expect(epsilonPost.thumbnail_url?.endsWith(".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 ends with png, to be sure its an image expect(post.thumbnail_url?.endsWith(".png")).toBeTruthy(); let epsilonPostRes = await resolvePost(epsilon, postRes.post_view.post); expect(epsilonPostRes.post).toBeDefined(); let epsilonPostRes2 = await waitUntil( () => getPost(epsilon, epsilonPostRes.post!.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 ends with png, to be sure its an image expect(epsilonPost.thumbnail_url?.endsWith(".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.actor_id, ); await followCommunity(beta, true, betaCommunity.community!.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, `![](${sampleImage})`, ); 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(`![](${sampleImage})`); let betaPost = await waitForPost( beta, post.post_view.post, res => 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(`![](${sampleImage})`); // 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); });