Skip to content

Commit a9b0416

Browse files
committed
add owner to Space, fix "create" policy for SpaceUser
1 parent 3938bc6 commit a9b0416

File tree

7 files changed

+64
-11
lines changed

7 files changed

+64
-11
lines changed

app/api/model/[...path]/route.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import { prisma } from 'server/db';
66
// create an enhanced Prisma client with user context
77
async function getPrisma() {
88
const authObj = await auth();
9-
return enhance(prisma, { user: authObj?.user });
9+
if (authObj?.user) {
10+
const user = await prisma.user.findUnique({ where: { id: authObj.user.id }, include: { memberships: true } });
11+
return enhance(prisma, { user });
12+
} else {
13+
return enhance(prisma, { user: authObj?.user });
14+
}
1015
}
1116

1217
const handler = NextRequestHandler({ getPrisma, useAppDir: true });

lib/hooks/__model_meta.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ const metadata = {
2222
name: "updatedAt",
2323
type: "DateTime",
2424
attributes: [{ "name": "@updatedAt", "args": [] }],
25+
}, owner: {
26+
name: "owner",
27+
type: "User",
28+
isDataModel: true,
29+
backLink: 'ownedSpaces',
30+
isRelationOwner: true,
31+
foreignKeyMapping: { "id": "ownerId" },
32+
}, ownerId: {
33+
name: "ownerId",
34+
type: "String",
35+
attributes: [{ "name": "@default", "args": [] }],
36+
defaultValueProvider: $default$Space$ownerId,
37+
isForeignKey: true,
38+
relationField: 'owner',
2539
}, name: {
2640
name: "name",
2741
type: "String",
@@ -85,7 +99,7 @@ const metadata = {
8599
name: "user",
86100
type: "User",
87101
isDataModel: true,
88-
backLink: 'spaces',
102+
backLink: 'memberships',
89103
isRelationOwner: true,
90104
foreignKeyMapping: { "id": "userId" },
91105
}, userId: {
@@ -140,8 +154,14 @@ const metadata = {
140154
name: "name",
141155
type: "String",
142156
isOptional: true,
143-
}, spaces: {
144-
name: "spaces",
157+
}, ownedSpaces: {
158+
name: "ownedSpaces",
159+
type: "Space",
160+
isDataModel: true,
161+
isArray: true,
162+
backLink: 'owner',
163+
}, memberships: {
164+
name: "memberships",
145165
type: "SpaceUser",
146166
isDataModel: true,
147167
isArray: true,
@@ -384,12 +404,16 @@ const metadata = {
384404
,
385405
deleteCascade: {
386406
space: ['SpaceUser', 'List'],
387-
user: ['SpaceUser', 'List', 'Todo', 'Account'],
407+
user: ['Space', 'SpaceUser', 'List', 'Todo', 'Account'],
388408
list: ['Todo'],
389409
}
390410
,
391411
authModel: 'User'
392412
};
413+
function $default$Space$ownerId(user: any): unknown {
414+
return user?.id;
415+
}
416+
393417
function $default$List$ownerId(user: any): unknown {
394418
return user?.id;
395419
}

lib/hooks/space.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ export function useSuspenseCountSpace<TArgs extends Prisma.SpaceCountArgs, TQuer
328328
return useSuspenseModelQuery<TQueryFnData, TData, TError>('Space', `${endpoint}/space/count`, args, options, fetch);
329329
}
330330

331-
export function useCheckSpace<TError = DefaultError>(args: { operation: PolicyCrudKind; where?: { id?: string; name?: string; slug?: string }; }, options?: (Omit<UseQueryOptions<boolean, TError, boolean>, 'queryKey'> & ExtraQueryOptions)) {
331+
export function useCheckSpace<TError = DefaultError>(args: { operation: PolicyCrudKind; where?: { id?: string; ownerId?: string; name?: string; slug?: string }; }, options?: (Omit<UseQueryOptions<boolean, TError, boolean>, 'queryKey'> & ExtraQueryOptions)) {
332332
const { endpoint, fetch } = getHooksContext();
333333
return useModelQuery<boolean, boolean, TError>('Space', `${endpoint}/space/check`, args, options, fetch);
334334
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
Warnings:
3+
4+
- Added the required column `ownerId` to the `Space` table without a default value. This is not possible if the table is not empty.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE "Space" ADD COLUMN "ownerId" TEXT NOT NULL;
9+
10+
-- AddForeignKey
11+
ALTER TABLE "Space" ADD CONSTRAINT "Space_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

prisma/schema.prisma

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ model Space {
2222
id String @id() @default(uuid())
2323
createdAt DateTime @default(now())
2424
updatedAt DateTime @updatedAt()
25+
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
26+
ownerId String
2527
name String
2628
slug String @unique()
2729
members SpaceUser[]
@@ -49,7 +51,8 @@ model User {
4951
emailVerified DateTime?
5052
password String?
5153
name String?
52-
spaces SpaceUser[]
54+
ownedSpaces Space[]
55+
memberships SpaceUser[]
5356
image String?
5457
lists List[]
5558
todos Todo[]

schema.zmodel

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ model Space {
4242
id String @id @default(uuid())
4343
createdAt DateTime @default(now())
4444
updatedAt DateTime @updatedAt
45+
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
46+
ownerId String @default(auth().id)
4547
name String @length(4, 50)
4648
slug String @unique @regex('^[0-9a-zA-Z]{4,16}$')
4749
members SpaceUser[]
@@ -77,8 +79,14 @@ model SpaceUser {
7779
// require login
7880
@@deny('all', auth() == null)
7981

80-
// space admin can create/update/delete
81-
@@allow('create,update,delete', space.members?[user == auth() && role == ADMIN])
82+
// space owner can add any one
83+
@@allow('create', space.owner == auth())
84+
85+
// space admin can add anyone but not himself
86+
@@allow('create', auth() != this.user && space.members?[user == auth() && role == ADMIN])
87+
88+
// space admin can update and delete
89+
@@allow('update,delete', space.members?[user == auth() && role == ADMIN])
8290

8391
// user can read entries for spaces which he's a member of
8492
@@allow('read', space.members?[user == auth()])
@@ -95,7 +103,8 @@ model User {
95103
emailVerified DateTime?
96104
password String? @password @omit
97105
name String?
98-
spaces SpaceUser[]
106+
ownedSpaces Space[]
107+
memberships SpaceUser[]
99108
image String? @url
100109
lists List[]
101110
todos Todo[]
@@ -107,7 +116,7 @@ model User {
107116
@@allow('create', true)
108117

109118
// can be read by users sharing any space
110-
@@allow('read', spaces?[space.members?[user == auth()]])
119+
@@allow('read', memberships?[space.members?[user == auth()]])
111120

112121
// full access by oneself
113122
@@allow('all', auth() == this)

server/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const authOptions: NextAuthConfig = {
6262
data: {
6363
name: `${user.name || user.email}'s space`,
6464
slug: nanoid(8),
65+
owner: { connect: { id: user.id } },
6566
members: {
6667
create: [
6768
{

0 commit comments

Comments
 (0)