cef8610925
* feat: add enabled column to UserFeatures and TeamFeatures for tri-state semantics - Add enabled Boolean column to UserFeatures model with default true - Add enabled Boolean column to TeamFeatures model with default true - Update FeaturesRepository to use tri-state semantics: - enabled=true: feature is explicitly enabled - enabled=false: feature is explicitly disabled (blocks inheritance) - No row: inherit from team/org level - Update SQL queries to check enabled=true for feature access - Add enableFeatureForTeam method to interface and implementation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update comments * add integration tests * add more test * select enabled only * no @default(true) * fix types and tests * add missing enabled * add missing enabled * rename enableFeatureForTeam to updateFeatureForTeam and support FeatureState * refactor: rename updateFeatureForTeam to setTeamFeatureState Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix integration test * fix tests * add more tests * add missing enabled --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
82 lines
1.9 KiB
TypeScript
82 lines
1.9 KiB
TypeScript
import type { PrismaClient } from "@calcom/prisma";
|
|
|
|
import type { TrpcSessionUser } from "../../../types";
|
|
import type { TAdminGetTeamsForFeatureSchema } from "./getTeamsForFeature.schema";
|
|
|
|
type GetTeamsOptions = {
|
|
ctx: {
|
|
user: NonNullable<TrpcSessionUser>;
|
|
prisma: PrismaClient;
|
|
};
|
|
input: TAdminGetTeamsForFeatureSchema;
|
|
};
|
|
|
|
export const getTeamsForFeatureHandler = async ({ ctx, input }: GetTeamsOptions) => {
|
|
const { prisma } = ctx;
|
|
const { featureId, limit = 10, cursor, searchTerm } = input;
|
|
|
|
const whereClause = {
|
|
isPlatform: false,
|
|
...(searchTerm
|
|
? {
|
|
OR: [
|
|
{ name: { contains: searchTerm, mode: "insensitive" as const } },
|
|
{ slug: { contains: searchTerm, mode: "insensitive" as const } },
|
|
],
|
|
}
|
|
: {}),
|
|
};
|
|
|
|
const [teams, assignedTeams] = await Promise.all([
|
|
prisma.team.findMany({
|
|
where: whereClause,
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
slug: true,
|
|
logoUrl: true,
|
|
parentId: true,
|
|
isOrganization: true,
|
|
parent: {
|
|
select: {
|
|
name: true,
|
|
logoUrl: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: {
|
|
name: "asc",
|
|
},
|
|
take: limit + 1,
|
|
...(cursor ? { skip: 1, cursor: { id: cursor } } : {}),
|
|
}),
|
|
prisma.teamFeatures.findMany({
|
|
where: {
|
|
featureId,
|
|
enabled: true,
|
|
},
|
|
select: {
|
|
teamId: true,
|
|
},
|
|
}),
|
|
]);
|
|
|
|
const assignedTeamIds = new Set(assignedTeams.map((tf) => tf.teamId));
|
|
|
|
let nextCursor: typeof cursor | undefined = undefined;
|
|
if (teams.length > limit) {
|
|
const nextItem = teams.pop();
|
|
nextCursor = nextItem?.id;
|
|
}
|
|
|
|
return {
|
|
teams: teams.map((team) => ({
|
|
...team,
|
|
hasFeature: assignedTeamIds.has(team.id),
|
|
})),
|
|
nextCursor,
|
|
};
|
|
};
|
|
|
|
export default getTeamsForFeatureHandler;
|