fix: read-after-write issues (#215)
* fix: read-after-write issues * fix: coderabbit comments * fix: clear cache on invite * fix: use primary after a read
This commit is contained in:
committed by
GitHub
parent
abacf66155
commit
f454449365
96
packages/db/src/services/access.service.ts
Normal file
96
packages/db/src/services/access.service.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { cacheable } from '@openpanel/redis';
|
||||
import { db } from '../prisma-client';
|
||||
import { getProjectById } from './project.service';
|
||||
|
||||
export const getProjectAccess = cacheable(
|
||||
'getProjectAccess',
|
||||
async ({
|
||||
userId,
|
||||
projectId,
|
||||
}: {
|
||||
userId: string;
|
||||
projectId: string;
|
||||
}) => {
|
||||
try {
|
||||
// Check if user has access to the project
|
||||
const project = await getProjectById(projectId);
|
||||
if (!project?.organizationId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const [projectAccess, member] = await Promise.all([
|
||||
db.$primary().projectAccess.findMany({
|
||||
where: {
|
||||
userId,
|
||||
organizationId: project.organizationId,
|
||||
},
|
||||
}),
|
||||
db.$primary().member.findFirst({
|
||||
where: {
|
||||
organizationId: project.organizationId,
|
||||
userId,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (projectAccess.length === 0 && member) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return projectAccess.find((item) => item.projectId === projectId);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
60 * 5,
|
||||
);
|
||||
|
||||
export const getOrganizationAccess = cacheable(
|
||||
'getOrganizationAccess',
|
||||
async ({
|
||||
userId,
|
||||
organizationId,
|
||||
}: {
|
||||
userId: string;
|
||||
organizationId: string;
|
||||
}) => {
|
||||
return db.$primary().member.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
organizationId,
|
||||
},
|
||||
});
|
||||
},
|
||||
60 * 5,
|
||||
);
|
||||
|
||||
export async function getClientAccess({
|
||||
userId,
|
||||
clientId,
|
||||
}: {
|
||||
userId: string;
|
||||
clientId: string;
|
||||
}) {
|
||||
const client = await db.client.findFirst({
|
||||
where: {
|
||||
id: clientId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!client) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (client.projectId) {
|
||||
return getProjectAccess({ userId, projectId: client.projectId });
|
||||
}
|
||||
|
||||
if (client.organizationId) {
|
||||
return getOrganizationAccess({
|
||||
userId,
|
||||
organizationId: client.organizationId,
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -5,7 +5,8 @@ import { chQuery, formatClickhouseDate } from '../clickhouse/client';
|
||||
import type { Invite, Prisma, ProjectAccess, User } from '../prisma-client';
|
||||
import { db } from '../prisma-client';
|
||||
import { createSqlBuilder } from '../sql-builder';
|
||||
import type { IServiceProject } from './project.service';
|
||||
import { getOrganizationAccess, getProjectAccess } from './access.service';
|
||||
import { type IServiceProject, getProjectById } from './project.service';
|
||||
export type IServiceOrganization = Awaited<
|
||||
ReturnType<typeof db.organization.findUniqueOrThrow>
|
||||
>;
|
||||
@@ -61,7 +62,7 @@ export async function getOrganizationByProjectId(projectId: string) {
|
||||
|
||||
export const getOrganizationByProjectIdCached = cacheable(
|
||||
getOrganizationByProjectId,
|
||||
60 * 60 * 24,
|
||||
60 * 5,
|
||||
);
|
||||
|
||||
export async function getInvites(organizationId: string) {
|
||||
@@ -168,8 +169,14 @@ export async function connectUserToOrganization({
|
||||
},
|
||||
});
|
||||
|
||||
await getOrganizationAccess.clear({
|
||||
userId: user.id,
|
||||
organizationId: invite.organizationId,
|
||||
});
|
||||
|
||||
if (invite.projectAccess.length > 0) {
|
||||
for (const projectId of invite.projectAccess) {
|
||||
await getProjectAccess.clear({ userId: user.id, projectId });
|
||||
await db.projectAccess.create({
|
||||
data: {
|
||||
projectId,
|
||||
|
||||
Reference in New Issue
Block a user