diff --git a/apps/backend/prisma/migrations/20240820045300_client_read_only_metadata/migration.sql b/apps/backend/prisma/migrations/20240820045300_client_read_only_metadata/migration.sql new file mode 100644 index 000000000..cf6860440 --- /dev/null +++ b/apps/backend/prisma/migrations/20240820045300_client_read_only_metadata/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "ProjectUser" ADD COLUMN "clientReadOnlyMetadata" JSONB; + +-- AlterTable +ALTER TABLE "Team" ADD COLUMN "clientMetadata" JSONB, +ADD COLUMN "clientReadOnlyMetadata" JSONB, +ADD COLUMN "serverMetadata" JSONB; diff --git a/apps/backend/prisma/schema.prisma b/apps/backend/prisma/schema.prisma index 145d4a091..c6d46439d 100644 --- a/apps/backend/prisma/schema.prisma +++ b/apps/backend/prisma/schema.prisma @@ -93,8 +93,11 @@ model Team { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - displayName String - profileImageUrl String? + displayName String + profileImageUrl String? + clientMetadata Json? + clientReadOnlyMetadata Json? + serverMetadata Json? project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) permissions Permission[] @@ -242,8 +245,9 @@ model ProjectUser { requiresTotpMfa Boolean @default(false) totpSecret Bytes? - serverMetadata Json? - clientMetadata Json? + clientMetadata Json? + clientReadOnlyMetadata Json? + serverMetadata Json? @@id([projectId, projectUserId]) } diff --git a/apps/backend/src/app/api/v1/teams/crud.tsx b/apps/backend/src/app/api/v1/teams/crud.tsx index f73925c8f..0a70190f3 100644 --- a/apps/backend/src/app/api/v1/teams/crud.tsx +++ b/apps/backend/src/app/api/v1/teams/crud.tsx @@ -18,6 +18,9 @@ export function teamPrismaToCrud(prisma: Prisma.TeamGetPayload<{}>) { display_name: prisma.displayName, profile_image_url: prisma.profileImageUrl, created_at_millis: prisma.createdAt.getTime(), + client_metadata: prisma.clientMetadata, + client_read_only_metadata: prisma.clientReadOnlyMetadata, + server_metadata: prisma.serverMetadata, }; } @@ -43,6 +46,10 @@ export const teamsCrudHandlers = createLazyProxy(() => createCrudHandlers(teamsC data: { displayName: data.display_name, projectId: auth.project.id, + profileImageUrl: data.profile_image_url, + clientMetadata: data.client_metadata === null ? Prisma.JsonNull : data.client_metadata, + clientReadOnlyMetadata: data.client_read_only_metadata === null ? Prisma.JsonNull : data.client_read_only_metadata, + serverMetadata: data.server_metadata === null ? Prisma.JsonNull : data.server_metadata, }, }); @@ -123,6 +130,9 @@ export const teamsCrudHandlers = createLazyProxy(() => createCrudHandlers(teamsC data: { displayName: data.display_name, profileImageUrl: data.profile_image_url, + clientMetadata: data.client_metadata === null ? Prisma.JsonNull : data.client_metadata, + clientReadOnlyMetadata: data.client_read_only_metadata === null ? Prisma.JsonNull : data.client_read_only_metadata, + serverMetadata: data.server_metadata === null ? Prisma.JsonNull : data.server_metadata, }, }); }); diff --git a/apps/backend/src/app/api/v1/users/crud.tsx b/apps/backend/src/app/api/v1/users/crud.tsx index 7f5089116..6fffbb55a 100644 --- a/apps/backend/src/app/api/v1/users/crud.tsx +++ b/apps/backend/src/app/api/v1/users/crud.tsx @@ -12,7 +12,6 @@ import { StackAssertionError, StatusError, captureError, throwErr } from "@stack import { hashPassword } from "@stackframe/stack-shared/dist/utils/password"; import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; import { teamPrismaToCrud, teamsCrudHandlers } from "../teams/crud"; -import { teamsCrud } from "@stackframe/stack-shared/dist/interface/crud/teams"; export const userFullInclude = { projectUserOAuthAccounts: { @@ -81,6 +80,7 @@ export const userPrismaToCrud = (prisma: Prisma.ProjectUserGetPayload<{ include: profile_image_url: prisma.profileImageUrl, signed_up_at_millis: prisma.createdAt.getTime(), client_metadata: prisma.clientMetadata, + client_read_only_metadata: prisma.clientReadOnlyMetadata, server_metadata: prisma.serverMetadata, has_password: !!prisma.passwordHash, auth_with_email: prisma.authWithEmail, @@ -169,6 +169,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC projectId: auth.project.id, displayName: data.display_name === undefined ? undefined : (data.display_name || null), clientMetadata: data.client_metadata === null ? Prisma.JsonNull : data.client_metadata, + clientReadOnlyMetadata: data.client_read_only_metadata === null ? Prisma.JsonNull : data.client_read_only_metadata, serverMetadata: data.server_metadata === null ? Prisma.JsonNull : data.server_metadata, primaryEmail: data.primary_email, primaryEmailVerified: data.primary_email_verified ?? false, @@ -266,6 +267,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC data: { displayName: data.display_name === undefined ? undefined : (data.display_name || null), clientMetadata: data.client_metadata === null ? Prisma.JsonNull : data.client_metadata, + clientReadOnlyMetadata: data.client_read_only_metadata === null ? Prisma.JsonNull : data.client_read_only_metadata, serverMetadata: data.server_metadata === null ? Prisma.JsonNull : data.server_metadata, primaryEmail: data.primary_email, primaryEmailVerified: data.primary_email_verified ?? (data.primary_email !== undefined ? false : undefined), diff --git a/apps/dashboard/prisma/schema.prisma b/apps/dashboard/prisma/schema.prisma index 145d4a091..c6d46439d 100644 --- a/apps/dashboard/prisma/schema.prisma +++ b/apps/dashboard/prisma/schema.prisma @@ -93,8 +93,11 @@ model Team { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - displayName String - profileImageUrl String? + displayName String + profileImageUrl String? + clientMetadata Json? + clientReadOnlyMetadata Json? + serverMetadata Json? project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) permissions Permission[] @@ -242,8 +245,9 @@ model ProjectUser { requiresTotpMfa Boolean @default(false) totpSecret Bytes? - serverMetadata Json? - clientMetadata Json? + clientMetadata Json? + clientReadOnlyMetadata Json? + serverMetadata Json? @@id([projectId, projectUserId]) } diff --git a/apps/e2e/tests/backend/endpoints/api/v1/auth/oauth/token.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/auth/oauth/token.test.ts index 9c84e04dc..bf30683bf 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/auth/oauth/token.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/auth/oauth/token.test.ts @@ -45,6 +45,7 @@ describe("with grant_type === 'authorization_code'", async () => { ], "auth_with_email": false, "client_metadata": null, + "client_read_only_metadata": null, "connected_accounts": [ { "provider": { diff --git a/apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts index 2ef4547ca..c508a16cd 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts @@ -67,10 +67,13 @@ it("invites a user to a team", async ({ expect }) => { "is_paginated": false, "items": [ { + "client_metadata": null, + "client_read_only_metadata": null, "created_at_millis": , "display_name": "New Team", "id": "", "profile_image_url": null, + "server_metadata": null, }, ], }, diff --git a/apps/e2e/tests/backend/endpoints/api/v1/team-memberships.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/team-memberships.test.ts index 647c3b719..6ec75b2b8 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/team-memberships.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/team-memberships.test.ts @@ -76,6 +76,7 @@ it("creates a team and manage users on the server", async ({ expect }) => { ], "auth_with_email": true, "client_metadata": null, + "client_read_only_metadata": null, "connected_accounts": [], "display_name": null, "has_password": false, @@ -102,6 +103,7 @@ it("creates a team and manage users on the server", async ({ expect }) => { ], "auth_with_email": true, "client_metadata": null, + "client_read_only_metadata": null, "connected_accounts": [], "display_name": null, "has_password": false, @@ -158,6 +160,7 @@ it("creates a team and manage users on the server", async ({ expect }) => { ], "auth_with_email": true, "client_metadata": null, + "client_read_only_metadata": null, "connected_accounts": [], "display_name": null, "has_password": false, diff --git a/apps/e2e/tests/backend/endpoints/api/v1/teams.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/teams.test.ts index 07b3e26ac..7f7807575 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/teams.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/teams.test.ts @@ -88,10 +88,13 @@ it("creates a team on the client", async ({ expect }) => { NiceResponse { "status": 201, "body": { + "client_metadata": null, + "client_read_only_metadata": null, "created_at_millis": , "display_name": "New Team", "id": "", "profile_image_url": null, + "server_metadata": null, }, "headers": Headers {