import { captureException } from "@sentry/nextjs"; import db from "@calcom/prisma"; import type { AppFlags } from "./config"; import type { IFeaturesRepository } from "./features.repository.interface"; import { getFeatureFlag } from "./server/utils"; export class FeaturesRepository implements IFeaturesRepository { async checkIfFeatureIsEnabledGlobally(slug: keyof AppFlags) { try { return await getFeatureFlag(db, slug); } catch (err) { captureException(err); throw err; } } async checkIfUserHasFeature(userId: number, slug: string) { try { /** * findUnique was failing in prismock tests, so I'm using findFirst instead * FIXME refactor when upgrading prismock * https://github.com/morintd/prismock/issues/592 */ const userHasFeature = await db.userFeatures.findFirst({ where: { userId, featureId: slug, }, }); if (userHasFeature) return true; // If the user doesn't have the feature, check if they belong to a team with the feature. // This also covers organizations, which are teams. const userBelongsToTeamWithFeature = await this.checkIfUserBelongsToTeamWithFeature(userId, slug); if (userBelongsToTeamWithFeature) return true; return false; } catch (err) { captureException(err); throw err; } } private async checkIfUserBelongsToTeamWithFeature(userId: number, slug: string) { try { const user = await db.user.findUnique({ where: { id: userId, teams: { some: { team: { features: { some: { featureId: slug, }, }, }, }, }, }, select: { id: true }, }); if (user) return true; return false; } catch (err) { captureException(err); throw err; } } async checkIfTeamHasFeature(teamId: number, featureId: keyof AppFlags) { try { const teamFeature = await db.teamFeatures.findUnique({ where: { teamId_featureId: { teamId, featureId } }, }); return !!teamFeature; } catch (err) { captureException(err); throw err; } } }