nextworks 0.1.0-alpha.11 → 0.1.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -9
- package/dist/kits/auth-core/.nextworks/docs/AUTH_CORE_README.md +3 -3
- package/dist/kits/auth-core/.nextworks/docs/AUTH_QUICKSTART.md +264 -244
- package/dist/kits/auth-core/app/(protected)/settings/profile/profile-form.tsx +120 -114
- package/dist/kits/auth-core/app/api/auth/forgot-password/route.ts +116 -114
- package/dist/kits/auth-core/app/api/auth/reset-password/route.ts +66 -63
- package/dist/kits/auth-core/app/api/auth/send-verify-email/route.ts +1 -1
- package/dist/kits/auth-core/app/api/users/[id]/route.ts +134 -127
- package/dist/kits/auth-core/app/auth/reset-password/page.tsx +186 -187
- package/dist/kits/auth-core/components/auth/dashboard.tsx +25 -2
- package/dist/kits/auth-core/components/auth/forgot-password-form.tsx +90 -90
- package/dist/kits/auth-core/components/auth/login-form.tsx +492 -467
- package/dist/kits/auth-core/components/auth/signup-form.tsx +28 -29
- package/dist/kits/auth-core/lib/auth.ts +46 -15
- package/dist/kits/auth-core/lib/forms/map-errors.ts +37 -11
- package/dist/kits/auth-core/lib/server/result.ts +45 -45
- package/dist/kits/auth-core/lib/validation/forms.ts +1 -2
- package/dist/kits/auth-core/package-deps.json +4 -2
- package/dist/kits/auth-core/types/next-auth.d.ts +1 -1
- package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +2 -8
- package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +18 -1
- package/dist/kits/blocks/app/templates/productlaunch/page.tsx +0 -2
- package/dist/kits/blocks/components/sections/FAQ.tsx +0 -1
- package/dist/kits/blocks/components/sections/Newsletter.tsx +2 -2
- package/dist/kits/blocks/components/ui/switch.tsx +78 -78
- package/dist/kits/blocks/components/ui/theme-selector.tsx +1 -1
- package/dist/kits/blocks/lib/themes.ts +1 -0
- package/dist/kits/blocks/package-deps.json +4 -4
- package/dist/kits/data/.nextworks/docs/DATA_QUICKSTART.md +128 -112
- package/dist/kits/data/.nextworks/docs/DATA_README.md +2 -1
- package/dist/kits/data/app/api/posts/[id]/route.ts +83 -83
- package/dist/kits/data/app/api/posts/route.ts +136 -138
- package/dist/kits/data/app/api/seed-demo/route.ts +1 -2
- package/dist/kits/data/app/api/users/[id]/route.ts +29 -17
- package/dist/kits/data/app/api/users/check-email/route.ts +1 -1
- package/dist/kits/data/app/api/users/check-unique/route.ts +30 -27
- package/dist/kits/data/app/api/users/route.ts +0 -2
- package/dist/kits/data/app/examples/demo/create-post-form.tsx +108 -106
- package/dist/kits/data/app/examples/demo/page.tsx +2 -1
- package/dist/kits/data/app/examples/demo/seed-demo-button.tsx +1 -1
- package/dist/kits/data/components/admin/posts-manager.tsx +727 -719
- package/dist/kits/data/components/admin/users-manager.tsx +435 -432
- package/dist/kits/data/lib/server/result.ts +5 -2
- package/dist/kits/data/package-deps.json +1 -1
- package/dist/kits/data/scripts/seed-demo.mjs +1 -2
- package/dist/kits/forms/app/api/wizard/route.ts +76 -71
- package/dist/kits/forms/app/examples/forms/server-action/page.tsx +78 -71
- package/dist/kits/forms/components/hooks/useCheckUnique.ts +85 -79
- package/dist/kits/forms/components/ui/form/form-control.tsx +28 -28
- package/dist/kits/forms/components/ui/form/form-description.tsx +23 -22
- package/dist/kits/forms/components/ui/form/form-item.tsx +21 -21
- package/dist/kits/forms/components/ui/form/form-label.tsx +24 -24
- package/dist/kits/forms/components/ui/form/form-message.tsx +28 -29
- package/dist/kits/forms/components/ui/switch.tsx +78 -78
- package/dist/kits/forms/lib/forms/map-errors.ts +1 -1
- package/dist/kits/forms/lib/validation/forms.ts +1 -2
- package/package.json +1 -1
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
9
9
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
10
10
|
"tailwind-merge": "^3.3.1",
|
|
11
|
-
"tw-animate-css": "^1.
|
|
11
|
+
"tw-animate-css": "^1.4.0",
|
|
12
12
|
"next-themes": "^0.4.6",
|
|
13
13
|
"motion": "^12.23.12",
|
|
14
14
|
"sonner": "^2.0.7",
|
|
15
|
-
"@nextworks/blocks-core": "0.1.0-alpha.
|
|
16
|
-
"@nextworks/blocks-sections": "0.1.0-alpha.
|
|
17
|
-
"@nextworks/blocks-templates": "0.1.0-alpha.
|
|
15
|
+
"@nextworks/blocks-core": "0.1.0-alpha.14",
|
|
16
|
+
"@nextworks/blocks-sections": "0.1.0-alpha.14",
|
|
17
|
+
"@nextworks/blocks-templates": "0.1.0-alpha.14"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"tailwindcss": "^4.1.12"
|
|
@@ -1,112 +1,128 @@
|
|
|
1
|
-
# nextworks — Data kit quickstart
|
|
2
|
-
|
|
3
|
-
This document explains how to use the Data (crud) kit in the nextworks starter project.
|
|
4
|
-
|
|
5
|
-
Prerequisites
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
npx nextworks add
|
|
16
|
-
npx nextworks add
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
- /
|
|
98
|
-
- /
|
|
99
|
-
- /
|
|
100
|
-
- /
|
|
101
|
-
-
|
|
102
|
-
- /
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
1
|
+
# nextworks — Data kit quickstart
|
|
2
|
+
|
|
3
|
+
This document explains how to use the Data (crud) kit in the nextworks starter project.
|
|
4
|
+
|
|
5
|
+
Prerequisites
|
|
6
|
+
|
|
7
|
+
- Prisma is required (this kit is Prisma-coupled by design).
|
|
8
|
+
- A running PostgreSQL database and `DATABASE_URL` set in `.env`.
|
|
9
|
+
- Auth kit installed and configured (NextAuth + Prisma). The Data kit relies on NextAuth session for access control.
|
|
10
|
+
|
|
11
|
+
- In the monorepo, this is already wired up.
|
|
12
|
+
- In your own app via the CLI, the recommended alpha setup is to install Blocks (with sections + templates) + Auth Core + Forms first, then Data:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx nextworks add blocks --sections --templates
|
|
16
|
+
npx nextworks add auth-core
|
|
17
|
+
npx nextworks add forms
|
|
18
|
+
npx nextworks add data
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
then follow the Prisma and `.env` steps below.
|
|
22
|
+
|
|
23
|
+
- Forms kit (optional but recommended) for form primitives.
|
|
24
|
+
|
|
25
|
+
Setup
|
|
26
|
+
|
|
27
|
+
1. Install dependencies and generate Prisma client:
|
|
28
|
+
|
|
29
|
+
npm install
|
|
30
|
+
npx prisma generate
|
|
31
|
+
|
|
32
|
+
2. Run migrations (creates User/Post tables):
|
|
33
|
+
|
|
34
|
+
Make sure you have merged the Auth + Data models into your `prisma/schema.prisma` before running migrations.
|
|
35
|
+
|
|
36
|
+
npx prisma migrate dev
|
|
37
|
+
|
|
38
|
+
3. Seed a demo admin user and posts locally (optional):
|
|
39
|
+
|
|
40
|
+
# Set env vars or use defaults
|
|
41
|
+
|
|
42
|
+
SEED_ADMIN_EMAIL=admin@example.com SEED_ADMIN_PASSWORD=password123 node ./scripts/seed-demo.mjs
|
|
43
|
+
|
|
44
|
+
4. Run the dev server:
|
|
45
|
+
|
|
46
|
+
npm run dev
|
|
47
|
+
|
|
48
|
+
### Windows + Prisma + Next 16 (Turbopack) note
|
|
49
|
+
|
|
50
|
+
If you are on **Windows** and have installed the **Auth Core** or **Data** kits (which use Prisma under the hood) on **Next 16+**, the Next dev server may need permission to create symlinks for the Prisma client. On Windows, this can cause errors like:
|
|
51
|
+
|
|
52
|
+
> `create symlink to ../../../../node_modules/@prisma/client`
|
|
53
|
+
> `Caused by: A required privilege is not held by the client. (os error 1314)`
|
|
54
|
+
|
|
55
|
+
If you see this (often surfaced as a 500 on `/api/auth/session` or a NextAuth `CLIENT_FETCH_ERROR`), do one of the following:
|
|
56
|
+
|
|
57
|
+
- **Recommended**: Enable **Developer Mode** in Windows (Settings → For developers → Developer mode). This allows symlinks in normal terminals.
|
|
58
|
+
- Or: Run your dev server from an **elevated PowerShell/terminal** ("Run as administrator").
|
|
59
|
+
|
|
60
|
+
After doing one of these, restart `npm run dev` and reload your app.
|
|
61
|
+
|
|
62
|
+
Usage & testing
|
|
63
|
+
|
|
64
|
+
- Sign in at /auth/login using the seeded admin credentials (admin@example.com / password123).
|
|
65
|
+
- Visit /admin/posts to create/edit/delete posts. The UI supports pagination, search (title contains), and sort by createdAt.
|
|
66
|
+
- Visit /admin/users to view users (admin-only).
|
|
67
|
+
|
|
68
|
+
Notes
|
|
69
|
+
|
|
70
|
+
- Server-side RBAC: all modifying APIs (POST/PUT/DELETE) require a valid session, and user-level checks ensure only authors or admins can modify posts. The users list API requires admin access.
|
|
71
|
+
- Published flag: posts have a `published` boolean in Prisma. The admin UI exposes the published checkbox when creating or editing posts.
|
|
72
|
+
|
|
73
|
+
Troubleshooting
|
|
74
|
+
|
|
75
|
+
- If users list returns 403, ensure your signed-in user has role = 'admin'. You can promote a user with Prisma Studio or by running:
|
|
76
|
+
|
|
77
|
+
npx prisma db executeRaw "UPDATE \"User\" SET role = 'admin' WHERE email = 'admin@example.com';"
|
|
78
|
+
|
|
79
|
+
- If migrations fail, try:
|
|
80
|
+
|
|
81
|
+
npx prisma migrate reset
|
|
82
|
+
|
|
83
|
+
Files & kit manifest
|
|
84
|
+
|
|
85
|
+
If you plan to package a Data kit, here are the primary files, API routes and components used by the Data example flows. This manifest is intended to help packaging and documentation — adjust paths if you extract the kit into another project.
|
|
86
|
+
|
|
87
|
+
Files
|
|
88
|
+
|
|
89
|
+
- app/api/posts/route.ts
|
|
90
|
+
- app/api/posts/[id]/route.ts
|
|
91
|
+
- app/api/users/route.ts
|
|
92
|
+
- app/api/users/[id]/route.ts
|
|
93
|
+
- app/api/users/check-unique/route.ts
|
|
94
|
+
- app/api/users/check-email/route.ts
|
|
95
|
+
- app/api/seed-demo/route.ts
|
|
96
|
+
- app/api/signup/route.ts
|
|
97
|
+
- components/admin/admin-header.tsx
|
|
98
|
+
- components/admin/posts-manager.tsx
|
|
99
|
+
- components/admin/users-manager.tsx
|
|
100
|
+
- app/(protected)/admin/users/page.tsx
|
|
101
|
+
- app/(protected)/admin/posts/page.tsx
|
|
102
|
+
- app/examples/demo/create-post-form.tsx
|
|
103
|
+
- app/examples/demo/page.tsx
|
|
104
|
+
- lib/prisma.ts
|
|
105
|
+
- lib/server/result.ts
|
|
106
|
+
- lib/utils.ts
|
|
107
|
+
- lib/validation/forms.ts
|
|
108
|
+
- scripts/seed-demo.mjs
|
|
109
|
+
|
|
110
|
+
API routes (list)
|
|
111
|
+
|
|
112
|
+
- /api/posts (GET/POST) -> app/api/posts/route.ts
|
|
113
|
+
- /api/posts/:id (GET/PUT/DELETE) -> app/api/posts/[id]/route.ts
|
|
114
|
+
- /api/users (GET/POST) -> app/api/users/route.ts
|
|
115
|
+
- /api/users/:id (GET/PUT/DELETE) -> app/api/users/[id]/route.ts
|
|
116
|
+
- /api/users/check-unique -> app/api/users/check-unique/route.ts
|
|
117
|
+
- /api/users/check-email -> app/api/users/check-email/route.ts
|
|
118
|
+
- /api/seed-demo -> app/api/seed-demo/route.ts
|
|
119
|
+
- /api/signup -> app/api/signup/route.ts
|
|
120
|
+
|
|
121
|
+
Notes
|
|
122
|
+
|
|
123
|
+
- The Data kit relies on NextAuth sessions for access control — see lib/auth-helpers.ts and lib/auth.ts for server-side helpers and RBAC checks.
|
|
124
|
+
- The API routes return ApiResult envelope objects (see lib/server/result.ts) and the client uses lib/forms/map-errors.ts to map server validation errors into react-hook-form where appropriate.
|
|
125
|
+
|
|
126
|
+
Feedback
|
|
127
|
+
|
|
128
|
+
- File issues in the repo; note that CLI packaging for the Data kit is not yet implemented — this quickstart is for the repository as-is.
|
|
@@ -75,7 +75,8 @@ If you choose a different database provider, update the `provider` field in your
|
|
|
75
75
|
Notes and important behavior
|
|
76
76
|
|
|
77
77
|
- Kit dependencies:
|
|
78
|
-
- Data depends on Auth (for RBAC/session) and Forms (for form primitives/validation).
|
|
78
|
+
- Data requires Prisma (this kit is Prisma-coupled by design) and depends on Auth (for RBAC/session) and Forms (for form primitives/validation).
|
|
79
|
+
- The CLI currently auto-installs `auth-core` and `forms` when you run `nextworks add data` to ensure the required pieces are present. If you prefer an interactive prompt instead of auto-install, the CLI can be adjusted to prompt (ask the maintainers).
|
|
79
80
|
- The kit's package-deps.json lists runtime and dev dependencies that the CLI will merge into the project's package.json; after installation you must run npm install in the project.
|
|
80
81
|
|
|
81
82
|
- Standalone admin components:
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import { prisma } from "@/lib/prisma";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { postSchema } from "@/lib/validation/forms";
|
|
4
|
-
import { jsonOk, jsonFail, jsonFromZod } from "@/lib/server/result";
|
|
5
|
-
import { getServerSession } from "next-auth";
|
|
6
|
-
import { authOptions } from "@/lib/auth";
|
|
7
|
-
|
|
8
|
-
// Ensure Prisma runs in Node.js (not Edge)
|
|
9
|
-
export const runtime = "nodejs";
|
|
10
|
-
|
|
11
|
-
type RouteContext = { params: Promise<{ id: string }> };
|
|
12
|
-
|
|
13
|
-
export async function PUT(req: Request, { params }: RouteContext) {
|
|
14
|
-
try {
|
|
15
|
-
const { id } = await params;
|
|
16
|
-
|
|
17
|
-
// Require authenticated session
|
|
18
|
-
const session = await getServerSession(authOptions);
|
|
19
|
-
if (!session?.user) {
|
|
20
|
-
return jsonFail("Unauthorized", { status: 401 });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Only admins or the post author may update
|
|
24
|
-
const post = await prisma.post.findUnique({ where: { id } });
|
|
25
|
-
if (!post) return jsonFail("Not found", { status: 404 });
|
|
26
|
-
|
|
27
|
-
const isAdmin = (session.user as { role?: string }).role === "admin";
|
|
28
|
-
const isAuthor = (session.user as { id?: string }).id === post.authorId;
|
|
29
|
-
if (!isAdmin && !isAuthor) {
|
|
30
|
-
return jsonFail("Forbidden", { status: 403 });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Validate only the fields we allow to update. Make them optional so partial updates (e.g. { published: true }) work.
|
|
34
|
-
const updateSchema = postSchema
|
|
35
|
-
.pick({ title: true, content: true, published: true })
|
|
36
|
-
.partial();
|
|
37
|
-
const body = await req.json();
|
|
38
|
-
const data = updateSchema.parse(body);
|
|
39
|
-
|
|
40
|
-
// Build Prisma update object only with provided fields to avoid overwriting with undefined
|
|
41
|
-
const updateData:
|
|
42
|
-
if (data.title !== undefined) updateData.title = data.title;
|
|
43
|
-
if (data.content !== undefined) updateData.content = data.content ?? null;
|
|
44
|
-
if (data.published !== undefined) updateData.published = data.published;
|
|
45
|
-
|
|
46
|
-
const updated = await prisma.post.update({
|
|
47
|
-
where: { id },
|
|
48
|
-
data: updateData,
|
|
49
|
-
});
|
|
50
|
-
return jsonOk(updated, { status: 200, message: "Post updated" });
|
|
51
|
-
} catch (error: unknown) {
|
|
52
|
-
if (error instanceof z.ZodError) {
|
|
53
|
-
return jsonFromZod(error, { status: 400, message: "Validation failed" });
|
|
54
|
-
}
|
|
55
|
-
return jsonFail("Failed to update post", { status: 500 });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export async function DELETE(_req: Request, { params }: RouteContext) {
|
|
60
|
-
try {
|
|
61
|
-
const { id } = await params; // await params
|
|
62
|
-
|
|
63
|
-
const session = await getServerSession(authOptions);
|
|
64
|
-
if (!session?.user) {
|
|
65
|
-
return jsonFail("Unauthorized", { status: 401 });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const post = await prisma.post.findUnique({ where: { id } });
|
|
69
|
-
if (!post) return jsonFail("Not found", { status: 404 });
|
|
70
|
-
|
|
71
|
-
const isAdmin = (session.user as { role?: string }).role === "admin";
|
|
72
|
-
const isAuthor = (session.user as { id?: string }).id === post.authorId;
|
|
73
|
-
if (!isAdmin && !isAuthor) {
|
|
74
|
-
return jsonFail("Forbidden", { status: 403 });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await prisma.post.delete({ where: { id } }); // If Int: id: Number(id)
|
|
78
|
-
return jsonOk({ ok: true }, { status: 200, message: "Post deleted" });
|
|
79
|
-
} catch (e) {
|
|
80
|
-
console.error("DELETE /api/posts/[id] error:", e);
|
|
81
|
-
return jsonFail("Failed to delete post", { status: 500 });
|
|
82
|
-
}
|
|
83
|
-
}
|
|
1
|
+
import { prisma } from "@/lib/prisma";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { postSchema } from "@/lib/validation/forms";
|
|
4
|
+
import { jsonOk, jsonFail, jsonFromZod } from "@/lib/server/result";
|
|
5
|
+
import { getServerSession } from "next-auth";
|
|
6
|
+
import { authOptions } from "@/lib/auth";
|
|
7
|
+
|
|
8
|
+
// Ensure Prisma runs in Node.js (not Edge)
|
|
9
|
+
export const runtime = "nodejs";
|
|
10
|
+
|
|
11
|
+
type RouteContext = { params: Promise<{ id: string }> };
|
|
12
|
+
|
|
13
|
+
export async function PUT(req: Request, { params }: RouteContext) {
|
|
14
|
+
try {
|
|
15
|
+
const { id } = await params;
|
|
16
|
+
|
|
17
|
+
// Require authenticated session
|
|
18
|
+
const session = await getServerSession(authOptions);
|
|
19
|
+
if (!session?.user) {
|
|
20
|
+
return jsonFail("Unauthorized", { status: 401 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Only admins or the post author may update
|
|
24
|
+
const post = await prisma.post.findUnique({ where: { id } });
|
|
25
|
+
if (!post) return jsonFail("Not found", { status: 404 });
|
|
26
|
+
|
|
27
|
+
const isAdmin = (session.user as { role?: string }).role === "admin";
|
|
28
|
+
const isAuthor = (session.user as { id?: string }).id === post.authorId;
|
|
29
|
+
if (!isAdmin && !isAuthor) {
|
|
30
|
+
return jsonFail("Forbidden", { status: 403 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Validate only the fields we allow to update. Make them optional so partial updates (e.g. { published: true }) work.
|
|
34
|
+
const updateSchema = postSchema
|
|
35
|
+
.pick({ title: true, content: true, published: true })
|
|
36
|
+
.partial();
|
|
37
|
+
const body = await req.json();
|
|
38
|
+
const data = updateSchema.parse(body);
|
|
39
|
+
|
|
40
|
+
// Build Prisma update object only with provided fields to avoid overwriting with undefined
|
|
41
|
+
const updateData: Parameters<typeof prisma.post.update>[0]["data"] = {};
|
|
42
|
+
if (data.title !== undefined) updateData.title = data.title;
|
|
43
|
+
if (data.content !== undefined) updateData.content = data.content ?? null;
|
|
44
|
+
if (data.published !== undefined) updateData.published = data.published;
|
|
45
|
+
|
|
46
|
+
const updated = await prisma.post.update({
|
|
47
|
+
where: { id },
|
|
48
|
+
data: updateData,
|
|
49
|
+
});
|
|
50
|
+
return jsonOk(updated, { status: 200, message: "Post updated" });
|
|
51
|
+
} catch (error: unknown) {
|
|
52
|
+
if (error instanceof z.ZodError) {
|
|
53
|
+
return jsonFromZod(error, { status: 400, message: "Validation failed" });
|
|
54
|
+
}
|
|
55
|
+
return jsonFail("Failed to update post", { status: 500 });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function DELETE(_req: Request, { params }: RouteContext) {
|
|
60
|
+
try {
|
|
61
|
+
const { id } = await params; // await params
|
|
62
|
+
|
|
63
|
+
const session = await getServerSession(authOptions);
|
|
64
|
+
if (!session?.user) {
|
|
65
|
+
return jsonFail("Unauthorized", { status: 401 });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const post = await prisma.post.findUnique({ where: { id } });
|
|
69
|
+
if (!post) return jsonFail("Not found", { status: 404 });
|
|
70
|
+
|
|
71
|
+
const isAdmin = (session.user as { role?: string }).role === "admin";
|
|
72
|
+
const isAuthor = (session.user as { id?: string }).id === post.authorId;
|
|
73
|
+
if (!isAdmin && !isAuthor) {
|
|
74
|
+
return jsonFail("Forbidden", { status: 403 });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await prisma.post.delete({ where: { id } }); // If Int: id: Number(id)
|
|
78
|
+
return jsonOk({ ok: true }, { status: 200, message: "Post deleted" });
|
|
79
|
+
} catch (e: unknown) {
|
|
80
|
+
console.error("DELETE /api/posts/[id] error:", e);
|
|
81
|
+
return jsonFail("Failed to delete post", { status: 500 });
|
|
82
|
+
}
|
|
83
|
+
}
|