From af7261a429763596fefa94daab1898fe07a3de67 Mon Sep 17 00:00:00 2001 From: motechFR Date: Wed, 21 Aug 2024 16:37:45 +0100 Subject: [PATCH 1/4] Add method to reliably upsert farcaster users --- .../ensureFarcasterUserExists.spec.ts | 133 ++++++++++++++++++ lib/farcaster/ensureFarcasterUserExists.ts | 98 +++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 lib/farcaster/__tests__/ensureFarcasterUserExists.spec.ts create mode 100644 lib/farcaster/ensureFarcasterUserExists.ts diff --git a/lib/farcaster/__tests__/ensureFarcasterUserExists.spec.ts b/lib/farcaster/__tests__/ensureFarcasterUserExists.spec.ts new file mode 100644 index 0000000000..196c20f587 --- /dev/null +++ b/lib/farcaster/__tests__/ensureFarcasterUserExists.spec.ts @@ -0,0 +1,133 @@ +import { DataNotFoundError } from '@charmverse/core/errors'; +import { prisma } from '@charmverse/core/prisma-client'; +import { testUtilsUser } from '@charmverse/core/test'; +import { shortWalletAddress } from '@root/lib/utils/blockchain'; + +import { isProfilePathAvailable } from 'lib/profile/isProfilePathAvailable'; +import { uid } from 'lib/utils/strings'; + +import type { TypedFarcasterUser } from '../ensureFarcasterUserExists'; +import { ensureFarcasterUserExists } from '../ensureFarcasterUserExists'; +import { getFarcasterUsers } from '../getFarcasterUsers'; + +jest.mock('../getFarcasterUsers'); +jest.mock('lib/utils/strings'); +jest.mock('lib/utils/blockchain'); +jest.mock('lib/profile/isProfilePathAvailable'); + +describe('ensureFarcasterUserExists', () => { + const fid = 12345; + + afterEach(async () => { + await prisma.farcasterUser.deleteMany(); + await prisma.user.deleteMany(); + }); + + it('should return existing Farcaster user if already in the database', async () => { + const user = await testUtilsUser.generateUser(); + + const existingFarcasterUser = await prisma.farcasterUser.create({ + data: { + fid, + user: { + connect: { + id: user.id + } + }, + account: { + username: 'testuser', + displayName: 'Test User', + bio: 'Bio of test user', + pfpUrl: 'testpfp.url' + } + } + }); + + const result = await ensureFarcasterUserExists({ fid }); + expect(result).toEqual(expect.objectContaining({ fid })); + }); + + it('should create a Farcaster user and link it to an existing user account', async () => { + const existingUser = await prisma.user.create({ + data: { + username: 'existinguser', + identityType: 'Farcaster', + path: 'existinguser-path', + claimed: true, + wallets: { + create: [{ address: '0xexistingwallet' }] + } + } + }); + + (getFarcasterUsers as jest.Mock).mockResolvedValue([ + { + fid, + username: 'farcasteruser', + custody_address: '0xexistingwallet', + display_name: 'farcaster user name', + profile: { bio: { text: 'Bio of farcaster user' } }, + pfp_url: 'farcaster.pfp.url' + } + ]); + + const result = await ensureFarcasterUserExists({ fid }); + expect(result).toMatchObject( + expect.objectContaining({ + createdAt: expect.any(Date), + updatedAt: expect.any(Date), + fid, + userId: existingUser.id, + account: { + username: 'farcasteruser', + displayName: 'farcaster user name', + bio: 'Bio of farcaster user', + pfpUrl: 'farcaster.pfp.url' + } + }) + ); + }); + + it('should create a new Farcaster user and a new user account if no existing user account found', async () => { + (getFarcasterUsers as jest.Mock).mockResolvedValue([ + { + fid, + username: 'newfarcasteruser', + custody_address: '0xnewwallet', + display_name: 'new farcaster user', + profile: { bio: { text: 'Bio of new farcaster user' } }, + pfp_url: 'newfarcaster.pfp.url' + } + ]); + + (shortWalletAddress as jest.Mock).mockReturnValue('0xnewwalle-...'); + (isProfilePathAvailable as jest.Mock).mockResolvedValue(true); + (uid as jest.Mock).mockReturnValue('new-uid'); + + const result = await ensureFarcasterUserExists({ fid }); + expect(result).toMatchObject( + expect.objectContaining({ + createdAt: expect.any(Date), + updatedAt: expect.any(Date), + fid, + userId: expect.any(String), + account: { + displayName: 'new farcaster user', + bio: 'Bio of new farcaster user', + pfpUrl: 'newfarcaster.pfp.url', + username: 'newfarcasteruser' + } + }) + ); + }); + + it('should throw DataNotFoundError if the Farcaster user is not found in the external service', async () => { + (getFarcasterUsers as jest.Mock).mockResolvedValue([]); + + await expect(ensureFarcasterUserExists({ fid })).rejects.toThrow(DataNotFoundError); + }); + + it('should throw an error for invalid fid input', async () => { + await expect(ensureFarcasterUserExists({ fid: null as unknown as number })).rejects.toThrow(); + }); +}); diff --git a/lib/farcaster/ensureFarcasterUserExists.ts b/lib/farcaster/ensureFarcasterUserExists.ts new file mode 100644 index 0000000000..8d3938e2c4 --- /dev/null +++ b/lib/farcaster/ensureFarcasterUserExists.ts @@ -0,0 +1,98 @@ +import { DataNotFoundError } from '@charmverse/core/errors'; +import type { FarcasterUser } from '@charmverse/core/prisma-client'; +import { prisma } from '@charmverse/core/prisma-client'; + +import { isProfilePathAvailable } from 'lib/profile/isProfilePathAvailable'; +import { shortWalletAddress } from 'lib/utils/blockchain'; +import { uid } from 'lib/utils/strings'; + +import { getFarcasterUsers } from './getFarcasterUsers'; + +export type TypedFarcasterUser = FarcasterUser & { + account: { + username: string; + displayName: string; + bio: string; + pfpUrl: string; + }; +}; + +export async function ensureFarcasterUserExists({ fid }: { fid: number }): Promise { + const existingFarcasterUser = await prisma.farcasterUser.findUnique({ + where: { + fid + } + }); + + if (existingFarcasterUser) { + return existingFarcasterUser as TypedFarcasterUser; + } + + const farcasterAccount = await getFarcasterUsers({ fids: [fid] }).then((users) => users[0]); + + if (!farcasterAccount) { + throw new DataNotFoundError(`Farcaster user ${fid} not found`); + } + + const existingUserAccount = await prisma.user.findFirst({ + where: { + wallets: { + some: { + address: { + in: [farcasterAccount.custody_address, ...(farcasterAccount.verified_addresses?.eth_addresses || [])] + } + } + } + } + }); + + if (existingUserAccount) { + const createdAccount = await prisma.farcasterUser.create({ + data: { + fid, + user: { + connect: { + id: existingUserAccount.id + } + }, + account: { + username: farcasterAccount.username, + displayName: farcasterAccount.display_name, + bio: farcasterAccount.profile.bio.text, + pfpUrl: farcasterAccount.pfp_url + } + } + }); + + return createdAccount as TypedFarcasterUser; + } + + const userPath = shortWalletAddress(farcasterAccount.custody_address).replace('…', '-'); + const isUserPathAvailable = await isProfilePathAvailable(userPath); + + const createdUser = await prisma.user.create({ + data: { + username: farcasterAccount.username, + identityType: 'Farcaster', + path: isUserPathAvailable ? userPath : uid(), + claimed: false, + avatar: farcasterAccount.pfp_url, + farcasterUser: { + create: { + fid, + account: { + username: farcasterAccount.username, + displayName: farcasterAccount.display_name, + bio: farcasterAccount.profile.bio.text, + pfpUrl: farcasterAccount.pfp_url + } + } + } + }, + select: { + farcasterUser: true + } + }); + + return createdUser.farcasterUser as TypedFarcasterUser; +} From 9ae88e48f4552b71fb84403fc92ad76e379497cd Mon Sep 17 00:00:00 2001 From: motechFR Date: Wed, 21 Aug 2024 16:51:02 +0100 Subject: [PATCH 2/4] Add display name defaults --- @connect-shared/lib/projects/createProject.ts | 137 ++---------------- @connect-shared/lib/projects/editProject.ts | 113 +-------------- @connect-shared/lib/projects/findProject.ts | 2 +- .../components/profile/ProfilePage.tsx | 2 +- .../profile/[username]/ProfileDetailsPage.tsx | 2 +- .../components/AddProjectMembersForm.tsx | 2 +- .../components/profile/ProfilePage.tsx | 2 +- .../profile/[username]/ProfileDetailsPage.tsx | 2 +- .../components/AddProjectMembersForm.tsx | 2 +- .../ensureFarcasterUserExists.spec.ts | 2 +- lib/farcaster/ensureFarcasterUserExists.ts | 25 +++- 11 files changed, 47 insertions(+), 244 deletions(-) diff --git a/@connect-shared/lib/projects/createProject.ts b/@connect-shared/lib/projects/createProject.ts index bcd42d96d2..419b40efe9 100644 --- a/@connect-shared/lib/projects/createProject.ts +++ b/@connect-shared/lib/projects/createProject.ts @@ -4,6 +4,7 @@ import type { OptionalPrismaTransaction, Prisma, Project, ProjectSource } from ' import { prisma } from '@charmverse/core/prisma-client'; import type { StatusAPIResponse } from '@farcaster/auth-client'; import { resolveENSName } from '@root/lib/blockchain'; +import { ensureFarcasterUserExists } from '@root/lib/farcaster/ensureFarcasterUserExists'; import { getFarcasterUsers } from '@root/lib/farcaster/getFarcasterUsers'; import { generatePagePathFromPathAndTitle } from '@root/lib/pages/utils'; import { stringToValidPath, uid } from '@root/lib/utils/strings'; @@ -43,131 +44,15 @@ export async function createProject({ } } - const farcasterAccounts = await tx.farcasterUser.findMany({ - where: { - fid: { - in: input.projectMembers.map(({ farcasterId }) => farcasterId) - } - }, - select: { - userId: true, - fid: true, - account: true - } - }); - - const teamLeadFarcasterAccount = farcasterAccounts.find( - (account) => account.userId === userId - ) as (typeof farcasterAccounts)[0]; - - const farcasterAccountsRecord: Record< - number, - { - userId: string; - account: StatusAPIResponse; - } - > = farcasterAccounts.reduce< - Record< - number, - { - userId: string; - account: StatusAPIResponse; - } - > - >((acc, { fid, userId: _userId, account }) => { - acc[fid] = { - userId: _userId, - account: account as unknown as StatusAPIResponse - }; - return acc; - }, {}); - - const projectMembers = ( - await Promise.all( - input.projectMembers.map(async (member) => { - if (farcasterAccountsRecord[member.farcasterId]) { - return { - userId: farcasterAccountsRecord[member.farcasterId].userId, - name: farcasterAccountsRecord[member.farcasterId].account.displayName as string, - farcasterId: member.farcasterId - }; - } - try { - const [farcasterProfile] = await getFarcasterUsers({ - fids: [member.farcasterId] - }); - if (!farcasterProfile) { - return null; - } - - const farcasterWalletUser = await tx.user.findFirst({ - where: { - wallets: { - some: { - address: { - in: [ - farcasterProfile.custody_address, - ...(farcasterProfile.verified_addresses ? farcasterProfile.verified_addresses.eth_addresses : []) - ].map((address) => address.toLowerCase()) - } - } - } - }, - select: { - id: true - } - }); - - if (farcasterWalletUser) { - return { - userId: farcasterWalletUser.id, - name: farcasterProfile.display_name, - farcasterId: member.farcasterId - }; - } - const username = farcasterProfile.username; - const displayName = farcasterProfile.display_name; - const bio = farcasterProfile.profile.bio.text; - const pfpUrl = farcasterProfile.pfp_url; - const fid = member.farcasterId; - - const newUser = await tx.user.create({ - data: { - id: v4(), - username, - identityType: 'Farcaster', - claimed: false, - avatar: farcasterProfile.pfp_url, - farcasterUser: { - create: { - account: { username, displayName, bio, pfpUrl }, - fid - } - }, - path: uid(), - profile: { - create: { - ...(bio && { description: bio || '' }) - } - } - } - }); - - return { - userId: newUser.id, - name: displayName, - farcasterId: member.farcasterId - }; - } catch (err) { - log.error('Error creating user', { - fid: member.farcasterId, - err - }); - return null; - } + const projectMembers = await Promise.all( + input.projectMembers.map((member) => + ensureFarcasterUserExists({ + fid: member.farcasterId }) ) - ).filter(isTruthy); + ); + + const teamLeadFarcasterAccount = projectMembers.find((member) => member.userId === userId); let path = stringToValidPath({ input: input.name ?? '', wordSeparator: '-', autoReplaceEmpty: false }); @@ -189,12 +74,12 @@ export async function createProject({ const projectMembersToCreate: Omit[] = [ ...projectMembers.map((member) => ({ - teamLead: member.farcasterId === teamLeadFarcasterAccount.fid, + teamLead: member.fid === teamLeadFarcasterAccount?.fid, updatedBy: userId, userId: member.userId, // This is necessary because some test data fids do not have a corresponding farcaster profile - name: member.name || '', - farcasterId: member.farcasterId + name: member.account.displayName || member.account.username, + farcasterId: member.fid })) ]; diff --git a/@connect-shared/lib/projects/editProject.ts b/@connect-shared/lib/projects/editProject.ts index 1db3ad77e8..1a7ce5beae 100644 --- a/@connect-shared/lib/projects/editProject.ts +++ b/@connect-shared/lib/projects/editProject.ts @@ -4,9 +4,11 @@ import type { Project } from '@charmverse/core/prisma-client'; import { prisma } from '@charmverse/core/prisma-client'; import type { StatusAPIResponse } from '@farcaster/auth-kit'; import { resolveENSName } from '@root/lib/blockchain'; +import { ensureFarcasterUserExists } from '@root/lib/farcaster/ensureFarcasterUserExists'; import { getFarcasterUsers } from '@root/lib/farcaster/getFarcasterUsers'; import { uid } from '@root/lib/utils/strings'; import { isTruthy } from '@root/lib/utils/types'; +import { meanBy } from 'lodash'; import { v4 } from 'uuid'; import type { FormValues } from './projectSchema'; @@ -70,112 +72,9 @@ export async function editProject({ userId, input }: { input: EditProjectValues; !currentProjectMembers.some((projectMember) => member.farcasterId === projectMember.user?.farcasterUser?.fid) ); - const farcasterAccountsRecord: Record< - number, - { - userId: string; - account: StatusAPIResponse; - } - > = inputProjectMembers.reduce< - Record< - number, - { - userId: string; - account: StatusAPIResponse; - } - > - >((acc, { fid, userId: _userId, account }) => { - acc[fid] = { - userId: _userId, - account: account as unknown as StatusAPIResponse - }; - return acc; - }, {}); - - const projectMembers = ( - await Promise.all( - newProjectMembers.map(async (member) => { - if (farcasterAccountsRecord[member.farcasterId]) { - return { - userId: farcasterAccountsRecord[member.farcasterId].userId, - name: farcasterAccountsRecord[member.farcasterId].account.displayName as string, - farcasterId: member.farcasterId - }; - } - try { - const [farcasterProfile] = await getFarcasterUsers({ - fids: [member.farcasterId] - }); - - if (!farcasterProfile) { - return null; - } - - const farcasterWalletUser = await prisma.user.findFirst({ - where: { - wallets: { - some: { - address: { - in: [ - farcasterProfile.custody_address, - ...(farcasterProfile.verified_addresses ? farcasterProfile.verified_addresses.eth_addresses : []) - ].map((address) => address.toLowerCase()) - } - } - } - } - }); - - if (farcasterWalletUser) { - return { - userId: farcasterWalletUser.id, - name: farcasterProfile.display_name, - farcasterId: member.farcasterId - }; - } - const username = farcasterProfile.username; - const displayName = farcasterProfile.display_name; - const bio = farcasterProfile.profile.bio.text; - const pfpUrl = farcasterProfile.pfp_url; - const fid = member.farcasterId; - - const newUser = await prisma.user.create({ - data: { - id: v4(), - username, - identityType: 'Farcaster', - claimed: false, - avatar: farcasterProfile.pfp_url, - farcasterUser: { - create: { - account: { username, displayName, bio, pfpUrl }, - fid - } - }, - path: uid(), - profile: { - create: { - ...(bio && { description: bio || '' }) - } - } - } - }); - - return { - userId: newUser.id, - name: displayName, - farcasterId: member.farcasterId - }; - } catch (err) { - log.error('Error creating user', { - fid: member.farcasterId, - err - }); - return null; - } - }) - ) - ).filter(isTruthy); + const projectMembers = await Promise.all( + newProjectMembers.map(async (member) => ensureFarcasterUserExists({ fid: member.farcasterId })) + ); const [editedProject] = await prisma.$transaction([ prisma.project.update({ @@ -206,7 +105,7 @@ export async function editProject({ userId, input }: { input: EditProjectValues; data: projectMembers.map((member) => ({ teamLead: false, updatedBy: userId, - name: member.name, + name: member.account.displayName || member.account.username, userId: member.userId, projectId: input.projectId })) diff --git a/@connect-shared/lib/projects/findProject.ts b/@connect-shared/lib/projects/findProject.ts index 2be354c367..cd06c3c96c 100644 --- a/@connect-shared/lib/projects/findProject.ts +++ b/@connect-shared/lib/projects/findProject.ts @@ -101,7 +101,7 @@ export async function findProject({ id, path }: { id?: string; path?: string }): ...member.user, userId: member.userId, teamLead: member.teamLead, - name: farcasterUser?.displayName || '', + name: farcasterUser?.displayName || farcasterUser?.username || '', farcasterId: member.user?.farcasterUser?.fid as number, farcasterUser: { fid: member.user?.farcasterUser?.fid, diff --git a/apps/connect/components/profile/ProfilePage.tsx b/apps/connect/components/profile/ProfilePage.tsx index 0396b09b66..3ef6cd6050 100644 --- a/apps/connect/components/profile/ProfilePage.tsx +++ b/apps/connect/components/profile/ProfilePage.tsx @@ -20,7 +20,7 @@ export async function ProfilePage({ user }: { user: LoggedInUser }) { Team Team { }); const result = await ensureFarcasterUserExists({ fid }); - expect(result).toEqual(expect.objectContaining({ fid })); + expect(result).toMatchObject(existingFarcasterUser); }); it('should create a Farcaster user and link it to an existing user account', async () => { diff --git a/lib/farcaster/ensureFarcasterUserExists.ts b/lib/farcaster/ensureFarcasterUserExists.ts index 8d3938e2c4..e39bb2d198 100644 --- a/lib/farcaster/ensureFarcasterUserExists.ts +++ b/lib/farcaster/ensureFarcasterUserExists.ts @@ -1,14 +1,18 @@ import { DataNotFoundError } from '@charmverse/core/errors'; +import { log } from '@charmverse/core/log'; import type { FarcasterUser } from '@charmverse/core/prisma-client'; import { prisma } from '@charmverse/core/prisma-client'; +import { v4 as uuid } from 'uuid'; import { isProfilePathAvailable } from 'lib/profile/isProfilePathAvailable'; import { shortWalletAddress } from 'lib/utils/blockchain'; import { uid } from 'lib/utils/strings'; +import { uploadUrlToS3, getUserS3FilePath } from '../aws/uploadToS3Server'; + import { getFarcasterUsers } from './getFarcasterUsers'; -export type TypedFarcasterUser = FarcasterUser & { +export type TypedFarcasterUser = Omit & { account: { username: string; displayName: string; @@ -46,6 +50,21 @@ export async function ensureFarcasterUserExists({ fid }: { fid: number }): Promi } }); + const userId = existingUserAccount?.id || uuid(); + + let avatar: string | null = farcasterAccount.pfp_url || ''; + + if (farcasterAccount.pfp_url) { + try { + ({ url: avatar } = await uploadUrlToS3({ + pathInS3: getUserS3FilePath({ userId, url: farcasterAccount.pfp_url }), + url: farcasterAccount.pfp_url + })); + } catch (error) { + log.warn('Error while uploading avatar to S3', error); + } + } + if (existingUserAccount) { const createdAccount = await prisma.farcasterUser.create({ data: { @@ -59,7 +78,7 @@ export async function ensureFarcasterUserExists({ fid }: { fid: number }): Promi username: farcasterAccount.username, displayName: farcasterAccount.display_name, bio: farcasterAccount.profile.bio.text, - pfpUrl: farcasterAccount.pfp_url + pfpUrl: avatar } } }); @@ -84,7 +103,7 @@ export async function ensureFarcasterUserExists({ fid }: { fid: number }): Promi username: farcasterAccount.username, displayName: farcasterAccount.display_name, bio: farcasterAccount.profile.bio.text, - pfpUrl: farcasterAccount.pfp_url + pfpUrl: avatar } } } From c7c3dbcde042caf46d8deea1759b9fe94c03fa98 Mon Sep 17 00:00:00 2001 From: motechFR Date: Wed, 21 Aug 2024 16:57:50 +0100 Subject: [PATCH 3/4] Fix linting error --- lib/farcaster/ensureFarcasterUserExists.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/farcaster/ensureFarcasterUserExists.ts b/lib/farcaster/ensureFarcasterUserExists.ts index e39bb2d198..12fd18b893 100644 --- a/lib/farcaster/ensureFarcasterUserExists.ts +++ b/lib/farcaster/ensureFarcasterUserExists.ts @@ -2,12 +2,11 @@ import { DataNotFoundError } from '@charmverse/core/errors'; import { log } from '@charmverse/core/log'; import type { FarcasterUser } from '@charmverse/core/prisma-client'; import { prisma } from '@charmverse/core/prisma-client'; +import { isProfilePathAvailable } from '@root/lib/profile/isProfilePathAvailable'; +import { shortWalletAddress } from '@root/lib/utils/blockchain'; +import { uid } from '@root/lib/utils/strings'; import { v4 as uuid } from 'uuid'; -import { isProfilePathAvailable } from 'lib/profile/isProfilePathAvailable'; -import { shortWalletAddress } from 'lib/utils/blockchain'; -import { uid } from 'lib/utils/strings'; - import { uploadUrlToS3, getUserS3FilePath } from '../aws/uploadToS3Server'; import { getFarcasterUsers } from './getFarcasterUsers'; From 23e257ef1a34df83bc095cb86daf2d9493aca877 Mon Sep 17 00:00:00 2001 From: motechFR Date: Wed, 21 Aug 2024 17:25:33 +0100 Subject: [PATCH 4/4] Address PR feedback --- @connect-shared/lib/projects/createProject.ts | 2 +- @connect-shared/lib/projects/editProject.ts | 22 ++----------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/@connect-shared/lib/projects/createProject.ts b/@connect-shared/lib/projects/createProject.ts index 419b40efe9..9a19f559e1 100644 --- a/@connect-shared/lib/projects/createProject.ts +++ b/@connect-shared/lib/projects/createProject.ts @@ -78,7 +78,7 @@ export async function createProject({ updatedBy: userId, userId: member.userId, // This is necessary because some test data fids do not have a corresponding farcaster profile - name: member.account.displayName || member.account.username, + name: (member.account.displayName || member.account.username)?.trim() || '', farcasterId: member.fid })) ]; diff --git a/@connect-shared/lib/projects/editProject.ts b/@connect-shared/lib/projects/editProject.ts index 1a7ce5beae..bb5b93f464 100644 --- a/@connect-shared/lib/projects/editProject.ts +++ b/@connect-shared/lib/projects/editProject.ts @@ -1,15 +1,9 @@ import { InvalidInputError } from '@charmverse/core/errors'; -import { log } from '@charmverse/core/log'; import type { Project } from '@charmverse/core/prisma-client'; import { prisma } from '@charmverse/core/prisma-client'; -import type { StatusAPIResponse } from '@farcaster/auth-kit'; import { resolveENSName } from '@root/lib/blockchain'; import { ensureFarcasterUserExists } from '@root/lib/farcaster/ensureFarcasterUserExists'; -import { getFarcasterUsers } from '@root/lib/farcaster/getFarcasterUsers'; -import { uid } from '@root/lib/utils/strings'; import { isTruthy } from '@root/lib/utils/types'; -import { meanBy } from 'lodash'; -import { v4 } from 'uuid'; import type { FormValues } from './projectSchema'; @@ -29,7 +23,7 @@ export async function editProject({ userId, input }: { input: EditProjectValues; } } - const [currentProjectMembers, inputProjectMembers] = await Promise.all([ + const [currentProjectMembers] = await Promise.all([ prisma.projectMember.findMany({ where: { projectId: input.projectId, @@ -47,18 +41,6 @@ export async function editProject({ userId, input }: { input: EditProjectValues; } } } - }), - prisma.farcasterUser.findMany({ - where: { - fid: { - in: input.projectMembers.map(({ farcasterId }) => farcasterId) - } - }, - select: { - userId: true, - fid: true, - account: true - } }) ]); @@ -73,7 +55,7 @@ export async function editProject({ userId, input }: { input: EditProjectValues; ); const projectMembers = await Promise.all( - newProjectMembers.map(async (member) => ensureFarcasterUserExists({ fid: member.farcasterId })) + newProjectMembers.map((member) => ensureFarcasterUserExists({ fid: member.farcasterId })) ); const [editedProject] = await prisma.$transaction([