Files
calendar/packages/trpc/server/routers/viewer/ooo/outOfOfficeEntriesList.handler.ts

181 lines
4.6 KiB
TypeScript

import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
import { getTranslation } from "@calcom/i18n/server";
import prisma from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/types";
import { TRPCError } from "@trpc/server";
import { type TOutOfOfficeEntriesListSchema } from "./outOfOfficeEntriesList.schema";
type GetOptions = {
ctx: {
user: NonNullable<TrpcSessionUser>;
};
input: TOutOfOfficeEntriesListSchema;
};
export const outOfOfficeEntriesList = async ({ ctx, input }: GetOptions) => {
const t = await getTranslation(ctx.user.locale, "common");
const {
cursor,
limit,
fetchTeamMembersEntries,
searchTerm,
endDateFilterStartRange,
endDateFilterEndRange,
} = input;
let fetchOOOEntriesForIds = [ctx.user.id];
let reportingUserIds = [0];
if (fetchTeamMembersEntries) {
// Get teams of context user
const teams = await prisma.membership.findMany({
where: {
userId: ctx.user.id,
accepted: true,
},
select: {
teamId: true,
role: true,
},
});
if (teams.length === 0) {
throw new TRPCError({ code: "NOT_FOUND", message: t("user_has_no_team_yet") });
}
const ownerOrAdminTeamIds = teams
.filter((team) => checkAdminOrOwner(team.role))
.map((team) => team.teamId);
// Fetch team member userIds
const teamMembers = await prisma.team.findMany({
where: {
id: {
in: teams.map((team) => team.teamId),
},
},
select: {
id: true,
members: {
select: {
userId: true,
accepted: true,
},
},
},
});
const userIds = teamMembers
.flatMap((team) => team.members.filter((member) => member.accepted).map((member) => member.userId))
.filter((id) => id !== ctx.user.id);
if (userIds.length === 0) {
throw new TRPCError({ code: "NOT_FOUND", message: t("no_team_members") });
}
fetchOOOEntriesForIds = userIds;
const adminTeams = teamMembers.filter(({ id }) => ownerOrAdminTeamIds.includes(id));
reportingUserIds = adminTeams.flatMap(({ members }) =>
members.filter(({ accepted, userId }) => accepted && userId !== ctx.user.id).map(({ userId }) => userId)
);
}
const whereClause = {
userId: {
in: fetchOOOEntriesForIds,
},
end: {
gte: endDateFilterStartRange ?? new Date().toISOString(),
lte: endDateFilterEndRange,
},
...(searchTerm
? {
OR: [
{ notes: { contains: searchTerm } },
{ reason: { reason: { contains: searchTerm } } },
{
toUser: {
OR: [{ email: { contains: searchTerm } }, { name: { contains: searchTerm } }],
},
},
...(fetchTeamMembersEntries
? [
{
user: {
OR: [{ email: { contains: searchTerm } }, { name: { contains: searchTerm } }],
},
},
]
: []),
],
}
: {}),
};
const getTotalEntries = await prisma.outOfOfficeEntry.count({
where: whereClause,
});
const outOfOfficeEntries = await prisma.outOfOfficeEntry.findMany({
where: whereClause,
select: {
id: true,
uuid: true,
start: true,
end: true,
toUserId: true,
toUser: {
select: {
username: true,
name: true,
email: true,
},
},
reason: {
select: {
id: true,
emoji: true,
reason: true,
userId: true,
},
},
notes: true,
showNotePublicly: true,
user: fetchTeamMembersEntries
? {
select: {
id: true,
username: true,
email: true,
avatarUrl: true,
name: true,
},
}
: false,
},
orderBy: {
start: "asc",
},
cursor: cursor ? { id: cursor } : undefined,
take: limit + 1,
});
let nextCursor: number | undefined = undefined;
if (outOfOfficeEntries && outOfOfficeEntries.length > limit) {
const nextItem = outOfOfficeEntries.pop();
nextCursor = nextItem?.id;
}
return {
rows:
outOfOfficeEntries.map((ooo) => {
return {
...ooo,
canEditAndDelete: fetchTeamMembersEntries ? reportingUserIds.includes(ooo.user.id) : true,
};
}) || [],
nextCursor,
meta: {
totalRowCount: getTotalEntries || 0,
},
};
};