Chore: Duplicate certain user fields to workspaceMember (#1514)
* Move certain user fields to workspaceMember Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Merge main Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Update the generated GraphQL Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Update hooks Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Refactor according to review Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> * Rework typing * Fix tests * Remove console logs --------- Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: chiazokam <chiazokamecheta@gmail.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -78,6 +78,10 @@ export class AbilityFactory {
|
||||
can(AbilityAction.Read, 'WorkspaceMember', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Delete, 'WorkspaceMember', { workspaceId: workspace.id });
|
||||
cannot(AbilityAction.Delete, 'WorkspaceMember', { userId: user.id });
|
||||
can(AbilityAction.Update, 'WorkspaceMember', {
|
||||
userId: user.id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
// Company
|
||||
can(AbilityAction.Read, 'Company', { workspaceId: workspace.id });
|
||||
|
||||
@ -89,11 +89,6 @@ export class AuthService {
|
||||
email: signUpInput.email,
|
||||
passwordHash,
|
||||
locale: 'en',
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Prisma.UserCreateArgs,
|
||||
workspace.id,
|
||||
@ -105,11 +100,6 @@ export class AuthService {
|
||||
email: signUpInput.email,
|
||||
passwordHash,
|
||||
locale: 'en',
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Prisma.UserCreateArgs);
|
||||
}
|
||||
|
||||
@ -67,6 +67,12 @@ export class UserService {
|
||||
|
||||
assert(workspace, 'workspace is missing', BadRequestException);
|
||||
|
||||
const userSettings = await this.prismaService.client.userSettings.create({
|
||||
data: { locale: 'en' },
|
||||
});
|
||||
|
||||
const settings = { connect: { id: userSettings.id } };
|
||||
|
||||
// Create user
|
||||
const user = await this.prismaService.client.user.upsert({
|
||||
where: {
|
||||
@ -74,12 +80,14 @@ export class UserService {
|
||||
},
|
||||
create: {
|
||||
...(args.data as Prisma.UserCreateInput),
|
||||
settings,
|
||||
|
||||
workspaceMember: {
|
||||
create: {
|
||||
workspace: {
|
||||
connect: { id: workspace.id },
|
||||
},
|
||||
settings,
|
||||
},
|
||||
},
|
||||
locale: 'en',
|
||||
|
||||
@ -2,6 +2,7 @@ import { Args, Query, Resolver, Mutation } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
|
||||
import { accessibleBy } from '@casl/prisma';
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
import { WorkspaceMember } from 'src/core/@generated/workspace-member/workspace-member.model';
|
||||
import { AbilityGuard } from 'src/guards/ability.guard';
|
||||
@ -9,6 +10,7 @@ import { CheckAbilities } from 'src/decorators/check-abilities.decorator';
|
||||
import {
|
||||
DeleteWorkspaceMemberAbilityHandler,
|
||||
ReadWorkspaceMemberAbilityHandler,
|
||||
UpdateWorkspaceMemberAbilityHandler,
|
||||
} from 'src/ability/handlers/workspace-member.ability-handler';
|
||||
import { FindManyWorkspaceMemberArgs } from 'src/core/@generated/workspace-member/find-many-workspace-member.args';
|
||||
import { UserAbility } from 'src/decorators/user-ability.decorator';
|
||||
@ -22,6 +24,7 @@ import { DeleteOneWorkspaceMemberArgs } from 'src/core/@generated/workspace-memb
|
||||
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
||||
import { AuthUser } from 'src/decorators/auth-user.decorator';
|
||||
import { User } from 'src/core/@generated/user/user.model';
|
||||
import { UpdateOneWorkspaceMemberArgs } from 'src/core/@generated/workspace-member/update-one-workspace-member.args';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => WorkspaceMember)
|
||||
@ -81,4 +84,19 @@ export class WorkspaceMemberResolver {
|
||||
select: prismaSelect.value,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => WorkspaceMember)
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(UpdateWorkspaceMemberAbilityHandler)
|
||||
async UpdateOneWorkspaceMember(
|
||||
@Args() args: UpdateOneWorkspaceMemberArgs,
|
||||
@PrismaSelector({ modelName: 'WorkspaceMember' })
|
||||
prismaSelect: PrismaSelect<'WorkspaceMember'>,
|
||||
): Promise<Partial<WorkspaceMember>> {
|
||||
return this.workspaceMemberService.update({
|
||||
data: args.data,
|
||||
where: args.where,
|
||||
select: prismaSelect.value,
|
||||
} as Prisma.WorkspaceMemberUpdateArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Made the column `idealCustomerProfile` on table `companies` required. This step will fail if there are existing NULL values in that column.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "activities" ADD COLUMN "workspaceMemberAssigneeId" TEXT,
|
||||
ADD COLUMN "workspaceMemberAuthorId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "attachments" ADD COLUMN "workspaceMemberAuthorId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "comments" ADD COLUMN "workspaceMemberAuthorId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "companies" ADD COLUMN "workspaceMemberAccountOwnerId" TEXT,
|
||||
ALTER COLUMN "idealCustomerProfile" SET NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "workspace_members" ADD COLUMN "settingsId" TEXT;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_settingsId_fkey" FOREIGN KEY ("settingsId") REFERENCES "user_settings"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "companies" ADD CONSTRAINT "companies_workspaceMemberAccountOwnerId_fkey" FOREIGN KEY ("workspaceMemberAccountOwnerId") REFERENCES "workspace_members"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "activities" ADD CONSTRAINT "activities_workspaceMemberAuthorId_fkey" FOREIGN KEY ("workspaceMemberAuthorId") REFERENCES "workspace_members"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "activities" ADD CONSTRAINT "activities_workspaceMemberAssigneeId_fkey" FOREIGN KEY ("workspaceMemberAssigneeId") REFERENCES "workspace_members"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comments" ADD CONSTRAINT "comments_workspaceMemberAuthorId_fkey" FOREIGN KEY ("workspaceMemberAuthorId") REFERENCES "workspace_members"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "attachments" ADD CONSTRAINT "attachments_workspaceMemberAuthorId_fkey" FOREIGN KEY ("workspaceMemberAuthorId") REFERENCES "workspace_members"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -138,7 +138,8 @@ model UserSettings {
|
||||
/// @Validator.IsString()
|
||||
locale String
|
||||
|
||||
user User?
|
||||
user User?
|
||||
WorkspaceMember WorkspaceMember[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@ -210,6 +211,15 @@ model WorkspaceMember {
|
||||
updatedAt DateTime @updatedAt
|
||||
Favorite Favorite[]
|
||||
|
||||
authoredActivities Activity[] @relation(name: "authoredActivities")
|
||||
assignedActivities Activity[] @relation(name: "assignedActivities")
|
||||
authoredAttachments Attachment[] @relation(name: "authoredAttachments")
|
||||
settings UserSettings? @relation(fields: [settingsId], references: [id])
|
||||
settingsId String?
|
||||
|
||||
companies Company[]
|
||||
comments Comment[]
|
||||
|
||||
@@map("workspace_members")
|
||||
}
|
||||
|
||||
@ -242,13 +252,15 @@ model Company {
|
||||
/// @Validator.IsOptional()
|
||||
employees Int?
|
||||
|
||||
people Person[]
|
||||
accountOwner User? @relation(fields: [accountOwnerId], references: [id], onDelete: SetNull)
|
||||
accountOwnerId String?
|
||||
people Person[]
|
||||
accountOwner User? @relation(fields: [accountOwnerId], references: [id], onDelete: SetNull)
|
||||
accountOwnerId String?
|
||||
workspaceMemberAccountOwner WorkspaceMember? @relation(fields: [workspaceMemberAccountOwnerId], references: [id], onDelete: SetNull)
|
||||
workspaceMemberAccountOwnerId String?
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspaceId String
|
||||
workspaceId String
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
deletedAt DateTime?
|
||||
@ -358,12 +370,20 @@ model Activity {
|
||||
attachments Attachment[]
|
||||
author User @relation(fields: [authorId], references: [id], name: "authoredActivities", onDelete: Cascade)
|
||||
authorId String
|
||||
assignee User? @relation(fields: [assigneeId], references: [id], name: "assignedActivities", onDelete: SetNull)
|
||||
assigneeId String?
|
||||
|
||||
workspaceMemberAuthor WorkspaceMember? @relation(fields: [workspaceMemberAuthorId], references: [id], name: "authoredActivities", onDelete: Cascade)
|
||||
workspaceMemberAuthorId String?
|
||||
|
||||
assignee User? @relation(fields: [assigneeId], references: [id], name: "assignedActivities", onDelete: SetNull)
|
||||
assigneeId String?
|
||||
|
||||
workspaceMemberAssignee WorkspaceMember? @relation(fields: [workspaceMemberAssigneeId], references: [id], name: "assignedActivities", onDelete: SetNull)
|
||||
workspaceMemberAssigneeId String?
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspaceId String
|
||||
workspaceId String
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
deletedAt DateTime?
|
||||
@ -381,8 +401,12 @@ model Comment {
|
||||
/// @Validator.IsString()
|
||||
body String
|
||||
|
||||
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
||||
authorId String
|
||||
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
||||
authorId String
|
||||
|
||||
workspaceMemberAuthor WorkspaceMember? @relation(fields: [workspaceMemberAuthorId], references: [id], onDelete: Cascade)
|
||||
workspaceMemberAuthorId String?
|
||||
|
||||
activity Activity? @relation(fields: [activityId], references: [id], onDelete: Cascade)
|
||||
activityId String?
|
||||
commentThreadId String?
|
||||
@ -550,8 +574,12 @@ model Attachment {
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspaceId String
|
||||
|
||||
author User @relation(fields: [authorId], references: [id], name: "authoredAttachments", onDelete: Cascade)
|
||||
authorId String
|
||||
author User @relation(fields: [authorId], references: [id], name: "authoredAttachments", onDelete: Cascade)
|
||||
authorId String
|
||||
|
||||
workspaceMemberAuthor WorkspaceMember? @relation(fields: [workspaceMemberAuthorId], references: [id], name: "authoredAttachments", onDelete: Cascade)
|
||||
workspaceMemberAuthorId String?
|
||||
|
||||
activity Activity @relation(fields: [activityId], references: [id], onDelete: Cascade)
|
||||
activityId String
|
||||
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
export const seedUsers = async (prisma: PrismaClient) => {
|
||||
await prisma.userSettings.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-9dcb1084c109' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'twenty-ge256b39-3ec3-4fe3-8997-9dcb1084c109',
|
||||
locale: 'en',
|
||||
},
|
||||
});
|
||||
await prisma.user.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-b76aa0bfc102' },
|
||||
update: {},
|
||||
@ -11,11 +19,7 @@ export const seedUsers = async (prisma: PrismaClient) => {
|
||||
locale: 'en',
|
||||
passwordHash:
|
||||
'$2b$10$66d.6DuQExxnrfI9rMqOg.U1XIYpagr6Lv05uoWLYbYmtK0HDIvS6', // Applecar2025
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-9dcb1084c109',
|
||||
avatarUrl: null,
|
||||
workspaceMember: {
|
||||
connectOrCreate: {
|
||||
@ -24,12 +28,21 @@ export const seedUsers = async (prisma: PrismaClient) => {
|
||||
},
|
||||
create: {
|
||||
workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-9dcb1084c109',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.userSettings.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-2c4a2035a215' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'twenty-ge256b39-3ec3-4fe3-8997-2c4a2035a215',
|
||||
locale: 'en',
|
||||
},
|
||||
});
|
||||
await prisma.user.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-b76aa0bfa408' },
|
||||
update: {},
|
||||
@ -39,21 +52,26 @@ export const seedUsers = async (prisma: PrismaClient) => {
|
||||
lastName: 'Ive',
|
||||
email: 'jony.ive@apple.dev',
|
||||
locale: 'en',
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-2c4a2035a215',
|
||||
avatarUrl: null,
|
||||
workspaceMember: {
|
||||
create: {
|
||||
id: 'twenty-7ef9d213-1c25-4d02-bf35-6aeccf7ea419',
|
||||
workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-2c4a2035a215',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.userSettings.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-8e1f2097b328' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'twenty-ge256b39-3ec3-4fe3-8997-8e1f2097b328',
|
||||
locale: 'en',
|
||||
},
|
||||
});
|
||||
await prisma.user.upsert({
|
||||
where: { id: 'twenty-gk256b39-3ec3-4fe3-8997-b76aa0bfa408' },
|
||||
update: {},
|
||||
@ -63,21 +81,26 @@ export const seedUsers = async (prisma: PrismaClient) => {
|
||||
lastName: 'Schiler',
|
||||
email: 'phil.schiler@apple.dev',
|
||||
locale: 'en',
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-8e1f2097b328',
|
||||
avatarUrl: null,
|
||||
workspaceMember: {
|
||||
create: {
|
||||
id: 'twenty-7ed9d213-1c25-4d02-bf35-6aeccf7ea419',
|
||||
workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-8e1f2097b328',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.userSettings.upsert({
|
||||
where: { id: 'twenty-ge256b39-3ec3-4fe3-8997-5e2d1049c430' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'twenty-ge256b39-3ec3-4fe3-8997-5e2d1049c430',
|
||||
locale: 'en',
|
||||
},
|
||||
});
|
||||
await prisma.user.upsert({
|
||||
where: { id: 'twenty-dev-gk256b39-3ec3-4fe3-8997-b76aa0boa408' },
|
||||
update: {},
|
||||
@ -87,15 +110,12 @@ export const seedUsers = async (prisma: PrismaClient) => {
|
||||
lastName: 'Bochet',
|
||||
email: 'charles@twenty.dev',
|
||||
locale: 'en',
|
||||
settings: {
|
||||
create: {
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-5e2d1049c430',
|
||||
workspaceMember: {
|
||||
create: {
|
||||
id: 'twenty-dev-7ed9d213-1c25-4d02-bf35-6aeccf7oa419',
|
||||
workspaceId: 'twenty-dev-7ed9d212-1c25-4d02-bf25-6aeccf7ea420',
|
||||
settingsId: 'twenty-ge256b39-3ec3-4fe3-8997-5e2d1049c430',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user