|
|
|
@@ -1,20 +1,16 @@
|
|
|
|
|
import { Prisma } from "@prisma/client";
|
|
|
|
|
// eslint-disable-next-line no-restricted-imports
|
|
|
|
|
import { orderBy } from "lodash";
|
|
|
|
|
|
|
|
|
|
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
|
|
|
|
|
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
|
|
|
|
import { isOrganization } from "@calcom/lib/entityPermissionUtils";
|
|
|
|
|
import { getTeamAvatarUrl, getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
|
|
|
|
|
import { getBookerBaseUrlSync } from "@calcom/lib/getBookerUrl/client";
|
|
|
|
|
import { getBookerBaseUrl } from "@calcom/lib/getBookerUrl/server";
|
|
|
|
|
import logger from "@calcom/lib/logger";
|
|
|
|
|
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
|
|
|
|
import { safeStringify } from "@calcom/lib/safeStringify";
|
|
|
|
|
import { EventTypeRepository } from "@calcom/lib/server/repository/eventType";
|
|
|
|
|
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
|
|
|
|
|
import { ProfileRepository } from "@calcom/lib/server/repository/profile";
|
|
|
|
|
import { UserRepository } from "@calcom/lib/server/repository/user";
|
|
|
|
|
import type { PrismaClient } from "@calcom/prisma";
|
|
|
|
|
import { baseEventTypeSelect } from "@calcom/prisma";
|
|
|
|
|
import { MembershipRole, SchedulingType } from "@calcom/prisma/enums";
|
|
|
|
|
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
|
|
|
|
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
|
|
|
@@ -24,7 +20,6 @@ import { TRPCError } from "@trpc/server";
|
|
|
|
|
import type { TrpcSessionUser } from "../../../trpc";
|
|
|
|
|
import type { TEventTypeInputSchema } from "./getByViewer.schema";
|
|
|
|
|
|
|
|
|
|
const log = logger.getSubLogger({ prefix: ["viewer.eventTypes.getByViewer"] });
|
|
|
|
|
type GetByViewerOptions = {
|
|
|
|
|
ctx: {
|
|
|
|
|
user: NonNullable<TrpcSessionUser>;
|
|
|
|
@@ -33,6 +28,57 @@ type GetByViewerOptions = {
|
|
|
|
|
input: TEventTypeInputSchema;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const userSelect = Prisma.validator<Prisma.UserSelect>()({
|
|
|
|
|
id: true,
|
|
|
|
|
username: true,
|
|
|
|
|
name: true,
|
|
|
|
|
organizationId: true,
|
|
|
|
|
avatarUrl: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const userEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
|
|
|
|
// Position is required by lodash to sort on it. Don't remove it, TS won't complain but it would silently break reordering
|
|
|
|
|
position: true,
|
|
|
|
|
hashedLink: true,
|
|
|
|
|
destinationCalendar: true,
|
|
|
|
|
userId: true,
|
|
|
|
|
team: {
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
// logo: true, // Skipping to avoid 4mb limit
|
|
|
|
|
bio: true,
|
|
|
|
|
hideBranding: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
metadata: true,
|
|
|
|
|
users: {
|
|
|
|
|
select: userSelect,
|
|
|
|
|
},
|
|
|
|
|
parentId: true,
|
|
|
|
|
hosts: {
|
|
|
|
|
select: {
|
|
|
|
|
user: {
|
|
|
|
|
select: userSelect,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
seatsPerTimeSlot: true,
|
|
|
|
|
...baseEventTypeSelect,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const teamEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
|
|
|
|
...userEventTypeSelect,
|
|
|
|
|
children: {
|
|
|
|
|
include: {
|
|
|
|
|
users: {
|
|
|
|
|
select: userSelect,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const compareMembership = (mship1: MembershipRole, mship2: MembershipRole) => {
|
|
|
|
|
const mshipToNumber = (mship: MembershipRole) =>
|
|
|
|
|
Object.keys(MembershipRole).findIndex((mmship) => mmship === mship);
|
|
|
|
@@ -40,54 +86,87 @@ export const compareMembership = (mship1: MembershipRole, mship2: MembershipRole
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) => {
|
|
|
|
|
const { prisma } = ctx;
|
|
|
|
|
|
|
|
|
|
await checkRateLimitAndThrowError({
|
|
|
|
|
identifier: `eventTypes:getByViewer:${ctx.user.id}`,
|
|
|
|
|
rateLimitingType: "common",
|
|
|
|
|
});
|
|
|
|
|
const lightProfile = ctx.user.profile;
|
|
|
|
|
|
|
|
|
|
const profile = await ProfileRepository.findByUpId(lightProfile.upId);
|
|
|
|
|
const isFilterSet = input?.filters && hasFilter(input.filters);
|
|
|
|
|
const isUpIdInFilter = input?.filters?.upIds?.includes(lightProfile.upId);
|
|
|
|
|
const shouldListUserEvents = !isFilterSet || isUpIdInFilter;
|
|
|
|
|
const [profileMemberships, profileEventTypes] = await Promise.all([
|
|
|
|
|
MembershipRepository.findAllByUpIdIncludeTeamWithMembersAndEventTypes(
|
|
|
|
|
{
|
|
|
|
|
upId: lightProfile.upId,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
const unenrichedUser = await prisma.user.findUnique({
|
|
|
|
|
where: {
|
|
|
|
|
id: ctx.user.id,
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
username: true,
|
|
|
|
|
name: true,
|
|
|
|
|
startTime: true,
|
|
|
|
|
endTime: true,
|
|
|
|
|
bufferTime: true,
|
|
|
|
|
avatar: true,
|
|
|
|
|
avatarUrl: true,
|
|
|
|
|
organizationId: true,
|
|
|
|
|
teams: {
|
|
|
|
|
where: {
|
|
|
|
|
accepted: true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
shouldListUserEvents
|
|
|
|
|
? EventTypeRepository.findAllByUpId(
|
|
|
|
|
select: {
|
|
|
|
|
role: true,
|
|
|
|
|
team: {
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
parentId: true,
|
|
|
|
|
metadata: true,
|
|
|
|
|
parent: true,
|
|
|
|
|
members: {
|
|
|
|
|
select: {
|
|
|
|
|
userId: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
eventTypes: {
|
|
|
|
|
select: teamEventTypeSelect,
|
|
|
|
|
orderBy: [
|
|
|
|
|
{
|
|
|
|
|
position: "desc",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "asc",
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
eventTypes: {
|
|
|
|
|
where: {
|
|
|
|
|
teamId: null,
|
|
|
|
|
userId: getPrismaWhereUserIdFromFilter(ctx.user.id, input?.filters),
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
...userEventTypeSelect,
|
|
|
|
|
},
|
|
|
|
|
orderBy: [
|
|
|
|
|
{
|
|
|
|
|
upId: lightProfile.upId,
|
|
|
|
|
position: "desc",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
where: {
|
|
|
|
|
teamId: null,
|
|
|
|
|
},
|
|
|
|
|
orderBy: [
|
|
|
|
|
{
|
|
|
|
|
position: "desc",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "asc",
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
: [],
|
|
|
|
|
]);
|
|
|
|
|
id: "asc",
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!profile) {
|
|
|
|
|
if (!unenrichedUser) {
|
|
|
|
|
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
|
|
|
|
|
}
|
|
|
|
|
const user = UserRepository.enrichUserWithItsProfileBuiltFromUser({ user: unenrichedUser });
|
|
|
|
|
|
|
|
|
|
const memberships = profileMemberships.map((membership) => ({
|
|
|
|
|
const memberships = user.teams.map((membership) => ({
|
|
|
|
|
...membership,
|
|
|
|
|
team: {
|
|
|
|
|
...membership.team,
|
|
|
|
@@ -95,43 +174,26 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
log.debug(
|
|
|
|
|
safeStringify({
|
|
|
|
|
profileMemberships,
|
|
|
|
|
profileEventTypes,
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
type UserEventTypes = (typeof user.eventTypes)[number];
|
|
|
|
|
type TeamEventTypeChildren = (typeof user.teams)[number]["team"]["eventTypes"][number];
|
|
|
|
|
|
|
|
|
|
type UserEventTypes = (typeof profileEventTypes)[number];
|
|
|
|
|
type TeamEventTypeChildren = NonNullable<(typeof profileEventTypes)[number]["team"]>["eventTypes"][number];
|
|
|
|
|
const mapEventType = async (eventType: UserEventTypes & Partial<TeamEventTypeChildren>) => ({
|
|
|
|
|
...eventType,
|
|
|
|
|
safeDescription: eventType?.description ? markdownToSafeHTML(eventType.description) : undefined,
|
|
|
|
|
users: await Promise.all(
|
|
|
|
|
(!!eventType?.hosts?.length ? eventType?.hosts.map((host) => host.user) : eventType.users).map(
|
|
|
|
|
async (u) =>
|
|
|
|
|
await UserRepository.enrichUserWithItsProfile({
|
|
|
|
|
user: u,
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
metadata: eventType.metadata ? EventTypeMetaDataSchema.parse(eventType.metadata) : null,
|
|
|
|
|
children: await Promise.all(
|
|
|
|
|
(eventType.children || []).map(async (c) => ({
|
|
|
|
|
...c,
|
|
|
|
|
users: await Promise.all(
|
|
|
|
|
c.users.map(
|
|
|
|
|
async (u) =>
|
|
|
|
|
await UserRepository.enrichUserWithItsProfile({
|
|
|
|
|
user: u,
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
}))
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
const mapEventType = (eventType: UserEventTypes & Partial<TeamEventTypeChildren>) => {
|
|
|
|
|
const users = !!eventType?.hosts?.length ? eventType?.hosts.map((host) => host.user) : eventType.users;
|
|
|
|
|
return {
|
|
|
|
|
...eventType,
|
|
|
|
|
safeDescription: eventType?.description ? markdownToSafeHTML(eventType.description) : undefined,
|
|
|
|
|
users: users.map((user) => UserRepository.enrichUserWithItsProfileBuiltFromUser({ user })),
|
|
|
|
|
metadata: eventType.metadata ? EventTypeMetaDataSchema.parse(eventType.metadata) : null,
|
|
|
|
|
children: eventType.children?.map((child) => {
|
|
|
|
|
return {
|
|
|
|
|
...child,
|
|
|
|
|
users: child.users.map((user) => UserRepository.enrichUserWithItsProfileBuiltFromUser({ user })),
|
|
|
|
|
};
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const userEventTypes = await Promise.all(profileEventTypes.map(mapEventType));
|
|
|
|
|
const userEventTypes = user.eventTypes.map(mapEventType);
|
|
|
|
|
|
|
|
|
|
type EventTypeGroup = {
|
|
|
|
|
teamId?: number | null;
|
|
|
|
@@ -139,8 +201,8 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
bookerUrl: string;
|
|
|
|
|
membershipRole?: MembershipRole | null;
|
|
|
|
|
profile: {
|
|
|
|
|
slug: (typeof profile)["username"] | null;
|
|
|
|
|
name: (typeof profile)["name"];
|
|
|
|
|
slug: (typeof user)["username"];
|
|
|
|
|
name: (typeof user)["name"];
|
|
|
|
|
image: string;
|
|
|
|
|
};
|
|
|
|
|
metadata: {
|
|
|
|
@@ -156,30 +218,16 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
(evType) => evType.schedulingType !== SchedulingType.MANAGED
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
log.debug(safeStringify({ profileMemberships, profileEventTypes, profile }));
|
|
|
|
|
|
|
|
|
|
log.debug(
|
|
|
|
|
"Filter Settings",
|
|
|
|
|
safeStringify({
|
|
|
|
|
isFilterSet,
|
|
|
|
|
isProfileIdInFilter: isUpIdInFilter,
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!isFilterSet || isUpIdInFilter) {
|
|
|
|
|
const bookerUrl = await getBookerBaseUrl(profile.organizationId ?? null);
|
|
|
|
|
if (!input?.filters || !hasFilter(input?.filters) || input?.filters?.userIds?.includes(user.id)) {
|
|
|
|
|
const bookerUrl = await getBookerBaseUrl(user.profile.organizationId);
|
|
|
|
|
eventTypeGroups.push({
|
|
|
|
|
teamId: null,
|
|
|
|
|
bookerUrl,
|
|
|
|
|
membershipRole: null,
|
|
|
|
|
profile: {
|
|
|
|
|
slug: profile.username,
|
|
|
|
|
name: profile.name,
|
|
|
|
|
image: getUserAvatarUrl({
|
|
|
|
|
username: profile.username,
|
|
|
|
|
avatarUrl: profile.avatarUrl,
|
|
|
|
|
profile: profile,
|
|
|
|
|
}),
|
|
|
|
|
slug: user.username,
|
|
|
|
|
name: user.name,
|
|
|
|
|
image: getUserAvatarUrl(user),
|
|
|
|
|
},
|
|
|
|
|
eventTypes: orderBy(unmanagedEventTypes, ["position", "id"], ["desc", "asc"]),
|
|
|
|
|
metadata: {
|
|
|
|
@@ -189,12 +237,12 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const teamMemberships = profileMemberships.map((membership) => ({
|
|
|
|
|
const teamMemberships = user.teams.map((membership) => ({
|
|
|
|
|
teamId: membership.team.id,
|
|
|
|
|
membershipRole: membership.role,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const filterTeamsEventTypesBasedOnInput = async (eventType: Awaited<ReturnType<typeof mapEventType>>) => {
|
|
|
|
|
const filterTeamsEventTypesBasedOnInput = (eventType: ReturnType<typeof mapEventType>) => {
|
|
|
|
|
if (!input?.filters || !hasFilter(input?.filters)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@@ -202,81 +250,76 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
};
|
|
|
|
|
eventTypeGroups = ([] as EventTypeGroup[]).concat(
|
|
|
|
|
eventTypeGroups,
|
|
|
|
|
await Promise.all(
|
|
|
|
|
memberships
|
|
|
|
|
.filter((mmship) => {
|
|
|
|
|
if (isOrganization({ team: mmship.team })) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if (!input?.filters || !hasFilter(input?.filters)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return input?.filters?.teamIds?.includes(mmship?.team?.id || 0) ?? false;
|
|
|
|
|
memberships
|
|
|
|
|
.filter((mmship) => {
|
|
|
|
|
const metadata = mmship.team.metadata;
|
|
|
|
|
if (metadata?.isOrganization) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if (!input?.filters || !hasFilter(input?.filters)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map(async (membership) => {
|
|
|
|
|
const orgMembership = teamMemberships.find(
|
|
|
|
|
(teamM) => teamM.teamId === membership.team.parentId
|
|
|
|
|
)?.membershipRole;
|
|
|
|
|
return input?.filters?.teamIds?.includes(mmship?.team?.id || 0) ?? false;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map((membership) => {
|
|
|
|
|
const orgMembership = teamMemberships.find(
|
|
|
|
|
(teamM) => teamM.teamId === membership.team.parentId
|
|
|
|
|
)?.membershipRole;
|
|
|
|
|
|
|
|
|
|
const team = {
|
|
|
|
|
...membership.team,
|
|
|
|
|
metadata: teamMetadataSchema.parse(membership.team.metadata),
|
|
|
|
|
};
|
|
|
|
|
const team = {
|
|
|
|
|
...membership.team,
|
|
|
|
|
metadata: teamMetadataSchema.parse(membership.team.metadata),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let slug;
|
|
|
|
|
let slug;
|
|
|
|
|
|
|
|
|
|
if (input?.forRoutingForms) {
|
|
|
|
|
// For Routing form we want to ensure that after migration of team to an org, the URL remains same for the team
|
|
|
|
|
// Once we solve this https://github.com/calcom/cal.com/issues/12399, we can remove this conditional change in slug
|
|
|
|
|
slug = `team/${team.slug}`;
|
|
|
|
|
} else {
|
|
|
|
|
// In an Org, a team can be accessed without /team prefix as well as with /team prefix
|
|
|
|
|
slug = team.slug ? (!team.parentId ? `team/${team.slug}` : `${team.slug}`) : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const eventTypes = await Promise.all(team.eventTypes.map(mapEventType));
|
|
|
|
|
return {
|
|
|
|
|
teamId: team.id,
|
|
|
|
|
parentId: team.parentId,
|
|
|
|
|
bookerUrl: getBookerBaseUrlSync(team.parent?.slug ?? null),
|
|
|
|
|
membershipRole:
|
|
|
|
|
orgMembership && compareMembership(orgMembership, membership.role)
|
|
|
|
|
? orgMembership
|
|
|
|
|
: membership.role,
|
|
|
|
|
profile: {
|
|
|
|
|
image: getTeamAvatarUrl({
|
|
|
|
|
slug: team.slug,
|
|
|
|
|
requestedSlug: team.metadata?.requestedSlug ?? null,
|
|
|
|
|
organizationId: team.parentId,
|
|
|
|
|
}),
|
|
|
|
|
name: team.name,
|
|
|
|
|
slug,
|
|
|
|
|
},
|
|
|
|
|
metadata: {
|
|
|
|
|
membershipCount: team.members.length,
|
|
|
|
|
readOnly:
|
|
|
|
|
membership.role ===
|
|
|
|
|
(team.parentId
|
|
|
|
|
? orgMembership && compareMembership(orgMembership, membership.role)
|
|
|
|
|
? orgMembership
|
|
|
|
|
: MembershipRole.MEMBER
|
|
|
|
|
: MembershipRole.MEMBER),
|
|
|
|
|
},
|
|
|
|
|
eventTypes: eventTypes
|
|
|
|
|
.filter(filterTeamsEventTypesBasedOnInput)
|
|
|
|
|
.filter((evType) => {
|
|
|
|
|
const res = evType.userId === null || evType.userId === ctx.user.id;
|
|
|
|
|
return res;
|
|
|
|
|
})
|
|
|
|
|
.filter((evType) =>
|
|
|
|
|
membership.role === MembershipRole.MEMBER
|
|
|
|
|
? evType.schedulingType !== SchedulingType.MANAGED
|
|
|
|
|
: true
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
if (input?.forRoutingForms) {
|
|
|
|
|
// For Routing form we want to ensure that after migration of team to an org, the URL remains same for the team
|
|
|
|
|
// Once we solve this https://github.com/calcom/cal.com/issues/12399, we can remove this conditional change in slug
|
|
|
|
|
slug = `team/${team.slug}`;
|
|
|
|
|
} else {
|
|
|
|
|
// In an Org, a team can be accessed without /team prefix as well as with /team prefix
|
|
|
|
|
slug = team.slug ? (!team.parentId ? `team/${team.slug}` : `${team.slug}`) : null;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
teamId: team.id,
|
|
|
|
|
parentId: team.parentId,
|
|
|
|
|
bookerUrl: getBookerBaseUrlSync(team.parent?.slug ?? null),
|
|
|
|
|
membershipRole:
|
|
|
|
|
orgMembership && compareMembership(orgMembership, membership.role)
|
|
|
|
|
? orgMembership
|
|
|
|
|
: membership.role,
|
|
|
|
|
profile: {
|
|
|
|
|
image: getTeamAvatarUrl({
|
|
|
|
|
slug: team.slug,
|
|
|
|
|
requestedSlug: team.metadata?.requestedSlug ?? null,
|
|
|
|
|
organizationId: team.parentId,
|
|
|
|
|
}),
|
|
|
|
|
name: team.name,
|
|
|
|
|
slug,
|
|
|
|
|
},
|
|
|
|
|
metadata: {
|
|
|
|
|
membershipCount: team.members.length,
|
|
|
|
|
readOnly:
|
|
|
|
|
membership.role ===
|
|
|
|
|
(team.parentId
|
|
|
|
|
? orgMembership && compareMembership(orgMembership, membership.role)
|
|
|
|
|
? orgMembership
|
|
|
|
|
: MembershipRole.MEMBER
|
|
|
|
|
: MembershipRole.MEMBER),
|
|
|
|
|
},
|
|
|
|
|
eventTypes: team.eventTypes
|
|
|
|
|
.map(mapEventType)
|
|
|
|
|
.filter(filterTeamsEventTypesBasedOnInput)
|
|
|
|
|
.filter((evType) => evType.userId === null || evType.userId === ctx.user.id)
|
|
|
|
|
.filter((evType) =>
|
|
|
|
|
membership.role === MembershipRole.MEMBER
|
|
|
|
|
? evType.schedulingType !== SchedulingType.MANAGED
|
|
|
|
|
: true
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
@@ -290,3 +333,15 @@ export const getByViewerHandler = async ({ ctx, input }: GetByViewerOptions) =>
|
|
|
|
|
})),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function getPrismaWhereUserIdFromFilter(
|
|
|
|
|
userId: number,
|
|
|
|
|
filters: NonNullable<TEventTypeInputSchema>["filters"] | undefined
|
|
|
|
|
) {
|
|
|
|
|
if (!filters || !hasFilter(filters)) {
|
|
|
|
|
return userId;
|
|
|
|
|
} else if (filters.userIds?.[0] === userId) {
|
|
|
|
|
return userId;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|