Skip to content

Commit

Permalink
feat: Expose asset manipulation endpoints in the REST API
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamedBassem committed Jan 4, 2025
1 parent eb0d821 commit 4439c91
Show file tree
Hide file tree
Showing 6 changed files with 630 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { NextRequest } from "next/server";
import { buildHandler } from "@/app/api/v1/utils/handler";
import { z } from "zod";

export const dynamic = "force-dynamic";

export const PUT = (
req: NextRequest,
params: { params: { bookmarkId: string; assetId: string } },
) =>
buildHandler({
req,
bodySchema: z.object({ assetId: z.string() }),
handler: async ({ api, body }) => {
await api.bookmarks.replaceAsset({
bookmarkId: params.params.bookmarkId,
oldAssetId: params.params.assetId,
newAssetId: body!.assetId,
});
return { status: 204 };
},
});

export const DELETE = (
req: NextRequest,
params: { params: { bookmarkId: string; assetId: string } },
) =>
buildHandler({
req,
handler: async ({ api }) => {
await api.bookmarks.detachAsset({
bookmarkId: params.params.bookmarkId,
assetId: params.params.assetId,
});
return { status: 204 };
},
});
36 changes: 36 additions & 0 deletions apps/web/app/api/v1/bookmarks/[bookmarkId]/assets/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NextRequest } from "next/server";
import { buildHandler } from "@/app/api/v1/utils/handler";

import { zAssetSchema } from "@hoarder/shared/types/bookmarks";

export const dynamic = "force-dynamic";

export const GET = (
req: NextRequest,
params: { params: { bookmarkId: string } },
) =>
buildHandler({
req,
handler: async ({ api }) => {
const resp = await api.bookmarks.getBookmark({
bookmarkId: params.params.bookmarkId,
});
return { status: 200, resp: { assets: resp.assets } };
},
});

export const POST = (
req: NextRequest,
params: { params: { bookmarkId: string } },
) =>
buildHandler({
req,
bodySchema: zAssetSchema,
handler: async ({ api, body }) => {
const asset = await api.bookmarks.attachAsset({
bookmarkId: params.params.bookmarkId,
asset: body!,
});
return { status: 201, resp: asset };
},
});
162 changes: 162 additions & 0 deletions packages/e2e_tests/tests/api/assets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,166 @@ describe("Assets API", () => {
);
expect(assetResponse.status).toBe(404);
});

it("should manage assets on a bookmark", async () => {
// Create a new bookmark
const { data: createdBookmark, error: createError } = await client.POST(
"/bookmarks",
{
body: {
type: "text",
title: "Test Bookmark",
text: "This is a test bookmark",
},
},
);

if (createError) {
console.error("Error creating bookmark:", createError);
throw createError;
}
if (!createdBookmark) {
throw new Error("Bookmark creation failed");
}

const file = new File(["test content"], "test.pdf", {
type: "application/pdf",
});

// Upload the asset
const uploadResponse1 = await uploadTestAsset(apiKey, port, file);
const uploadResponse2 = await uploadTestAsset(apiKey, port, file);
const uploadResponse3 = await uploadTestAsset(apiKey, port, file);

// Attach first asset
const { data: firstAsset, response: attachFirstRes } = await client.POST(
"/bookmarks/{bookmarkId}/assets",
{
params: {
path: {
bookmarkId: createdBookmark.id,
},
},
body: {
id: uploadResponse1.assetId,
assetType: "bannerImage",
},
},
);

expect(attachFirstRes.status).toBe(201);
expect(firstAsset).toEqual({
id: uploadResponse1.assetId,
assetType: "bannerImage",
});

// Attach second asset
const { data: secondAsset, response: attachSecondRes } = await client.POST(
"/bookmarks/{bookmarkId}/assets",
{
params: {
path: {
bookmarkId: createdBookmark.id,
},
},
body: {
id: uploadResponse2.assetId,
assetType: "bannerImage",
},
},
);

expect(attachSecondRes.status).toBe(201);
expect(secondAsset).toEqual({
id: uploadResponse2.assetId,
assetType: "bannerImage",
});

// Get bookmark and verify assets
const { data: bookmarkWithAssets } = await client.GET(
"/bookmarks/{bookmarkId}",
{
params: {
path: {
bookmarkId: createdBookmark.id,
},
},
},
);

expect(bookmarkWithAssets?.assets).toEqual(
expect.arrayContaining([
{ id: uploadResponse1.assetId, assetType: "bannerImage" },
{ id: uploadResponse2.assetId, assetType: "bannerImage" },
]),
);

// Replace first asset
const { response: replaceRes } = await client.PUT(
"/bookmarks/{bookmarkId}/assets/{assetId}",
{
params: {
path: {
bookmarkId: createdBookmark.id,
assetId: uploadResponse1.assetId,
},
},
body: {
assetId: uploadResponse3.assetId,
},
},
);

expect(replaceRes.status).toBe(204);

// Verify replacement
const { data: bookmarkAfterReplace } = await client.GET(
"/bookmarks/{bookmarkId}",
{
params: {
path: {
bookmarkId: createdBookmark.id,
},
},
},
);

expect(bookmarkAfterReplace?.assets).toEqual(
expect.arrayContaining([
{ id: uploadResponse3.assetId, assetType: "bannerImage" },
{ id: uploadResponse2.assetId, assetType: "bannerImage" },
]),
);

// Detach second asset
const { response: detachRes } = await client.DELETE(
"/bookmarks/{bookmarkId}/assets/{assetId}",
{
params: {
path: {
bookmarkId: createdBookmark.id,
assetId: uploadResponse2.assetId,
},
},
},
);

expect(detachRes.status).toBe(204);

// Verify detachment
const { data: bookmarkAfterDetach } = await client.GET(
"/bookmarks/{bookmarkId}",
{
params: {
path: {
bookmarkId: createdBookmark.id,
},
},
},
);

expect(bookmarkAfterDetach?.assets).toEqual([
{ id: uploadResponse3.assetId, assetType: "bannerImage" },
]);
});
});
Loading

0 comments on commit 4439c91

Please sign in to comment.