perf: Server-Side Data Fetching in App Router: /workflows (#16563)
* wip * complete server side fetching for app router * fix type error * fix * address comments --------- Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
This commit is contained in:
1 parent
d9777a3011
commit
976013512c
10 files changed
+359
-195
No files matched your search
@@ -1,18 +1,25 @@
|
||||
import { withAppDirSsg } from "app/WithAppDirSsg";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { headers, cookies } from "next/headers";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound } from "next/navigation";
|
||||
import { z } from "zod";
|
||||
|
||||
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
|
||||
import LegacyPage from "@calcom/features/ee/workflows/pages/workflow";
|
||||
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import { getStaticProps } from "@lib/workflows/[workflow]/getStaticProps";
|
||||
const querySchema = z.object({
|
||||
workflow: z.string(),
|
||||
});
|
||||
|
||||
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
|
||||
const { workflow: id } = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||
const workflow = await WorkflowRepository.getById({ id: +id });
|
||||
const parsed = querySchema.safeParse({ ...params, ...searchParams });
|
||||
if (!parsed.success) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const workflow = await WorkflowRepository.getById({ id: +parsed.data.workflow });
|
||||
|
||||
return await _generateMetadata(
|
||||
() => (workflow && workflow.name ? workflow.name : "Untitled"),
|
||||
@@ -20,11 +27,38 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const getData = withAppDirSsg(getStaticProps);
|
||||
|
||||
export const generateStaticParams = () => [];
|
||||
|
||||
export default WithLayout({ getLayout: null, getData, Page: LegacyPage })<"P">;
|
||||
const Page = async ({ params, searchParams }: PageProps) => {
|
||||
const session = await getServerSession(AUTH_OPTIONS);
|
||||
const user = session?.user;
|
||||
const parsed = querySchema.safeParse({ ...params, ...searchParams });
|
||||
if (!parsed.success) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const workflow = await WorkflowRepository.getById({ id: +parsed.data.workflow });
|
||||
let verifiedEmails, verifiedNumbers;
|
||||
try {
|
||||
verifiedEmails = await WorkflowRepository.getVerifiedEmails({
|
||||
userEmail: user?.email ?? null,
|
||||
userId: user?.id ?? null,
|
||||
teamId: workflow?.team?.id,
|
||||
});
|
||||
} catch (err) {}
|
||||
try {
|
||||
verifiedNumbers = await WorkflowRepository.getVerifiedNumbers({
|
||||
userId: user?.id ?? null,
|
||||
teamId: workflow?.team?.id,
|
||||
});
|
||||
} catch (err) {}
|
||||
|
||||
return (
|
||||
<LegacyPage workflowData={workflow} verifiedEmails={verifiedEmails} verifiedNumbers={verifiedNumbers} />
|
||||
);
|
||||
};
|
||||
|
||||
export default WithLayout({ getLayout: null, ServerPage: Page });
|
||||
export const dynamic = "force-static";
|
||||
// generate segments on demand
|
||||
export const dynamicParams = true;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
|
||||
import LegacyPage from "@calcom/features/ee/workflows/pages/index";
|
||||
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
|
||||
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
await _generateMetadata(
|
||||
@@ -9,4 +14,23 @@ export const generateMetadata = async () =>
|
||||
(t) => t("workflows_to_automate_notifications")
|
||||
);
|
||||
|
||||
export default WithLayout({ getLayout: null, Page: LegacyPage })<"P">;
|
||||
const Page = async ({ params, searchParams }: PageProps) => {
|
||||
const session = await getServerSession(AUTH_OPTIONS);
|
||||
const user = session?.user;
|
||||
|
||||
const filters = getTeamsFiltersFromQuery({ ...searchParams, ...params });
|
||||
|
||||
let filteredList;
|
||||
try {
|
||||
filteredList = await WorkflowRepository.getFilteredList({
|
||||
userId: user?.id,
|
||||
input: {
|
||||
filters,
|
||||
},
|
||||
});
|
||||
} catch (err) {}
|
||||
|
||||
return <LegacyPage filteredList={filteredList} />;
|
||||
};
|
||||
|
||||
export default WithLayout({ getLayout: null, ServerPage: Page })<"P">;
|
||||
@@ -8,7 +8,7 @@ const querySchema = z.object({
|
||||
export const getStaticProps: GetStaticProps = (ctx) => {
|
||||
const params = querySchema.safeParse(ctx.params);
|
||||
console.log("Built workflow page:", params);
|
||||
if (!params.success) return { notFound: true };
|
||||
if (!params.success) return { notFound: true } as const;
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import type { GetStaticPaths } from "next";
|
||||
|
||||
import Workflow from "@calcom/features/ee/workflows/pages/workflow";
|
||||
|
||||
@@ -11,6 +11,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import type { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { AnimatedPopover, Avatar, CreateButtonWithTeamsList, showToast } from "@calcom/ui";
|
||||
|
||||
@@ -22,16 +23,27 @@ import EmptyScreen from "../components/EmptyScreen";
|
||||
import SkeletonLoader from "../components/SkeletonLoaderList";
|
||||
import WorkflowList from "../components/WorkflowListPage";
|
||||
|
||||
function WorkflowsPage() {
|
||||
type PageProps = {
|
||||
filteredList?: Awaited<ReturnType<typeof WorkflowRepository.getFilteredList>>;
|
||||
};
|
||||
|
||||
function WorkflowsPage({ filteredList }: PageProps) {
|
||||
const { t } = useLocale();
|
||||
const session = useSession();
|
||||
const router = useRouter();
|
||||
const routerQuery = useRouterQuery();
|
||||
const filters = getTeamsFiltersFromQuery(routerQuery);
|
||||
|
||||
const queryRes = trpc.viewer.workflows.filteredList.useQuery({
|
||||
filters,
|
||||
});
|
||||
const { data, isPending: _isPending } = trpc.viewer.workflows.filteredList.useQuery(
|
||||
{
|
||||
filters,
|
||||
},
|
||||
{
|
||||
enabled: !filteredList,
|
||||
}
|
||||
);
|
||||
const filteredWorkflows = filteredList ?? data;
|
||||
const isPending = filteredList ? false : _isPending;
|
||||
|
||||
const createMutation = trpc.viewer.workflows.create.useMutation({
|
||||
onSuccess: async ({ workflow }) => {
|
||||
@@ -74,7 +86,7 @@ function WorkflowsPage() {
|
||||
) : null
|
||||
}>
|
||||
<>
|
||||
{queryRes.data?.totalCount ? (
|
||||
{filteredWorkflows?.totalCount ? (
|
||||
<div className="flex">
|
||||
<TeamsFilter />
|
||||
<div className="mb-4 ml-auto">
|
||||
@@ -90,11 +102,11 @@ function WorkflowsPage() {
|
||||
</div>
|
||||
) : null}
|
||||
<FilterResults
|
||||
queryRes={queryRes}
|
||||
queryRes={{ isPending, data: filteredWorkflows }}
|
||||
emptyScreen={<EmptyScreen isFilteredView={false} />}
|
||||
noResultsScreen={<EmptyScreen isFilteredView={true} />}
|
||||
SkeletonLoader={SkeletonLoader}>
|
||||
<WorkflowList workflows={queryRes.data?.filtered} />
|
||||
<WorkflowList workflows={filteredWorkflows?.filtered} />
|
||||
</FilterResults>
|
||||
</>
|
||||
</ShellMain>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SENDER_ID } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import type { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import type { TimeUnit, WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { MembershipRole, WorkflowActions } from "@calcom/prisma/enums";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
@@ -37,7 +38,17 @@ export type FormValues = {
|
||||
selectAll: boolean;
|
||||
};
|
||||
|
||||
function WorkflowPage() {
|
||||
type PageProps = {
|
||||
workflowData?: Awaited<ReturnType<typeof WorkflowRepository.getById>>;
|
||||
verifiedNumbers?: Awaited<ReturnType<typeof WorkflowRepository.getVerifiedNumbers>>;
|
||||
verifiedEmails?: Awaited<ReturnType<typeof WorkflowRepository.getVerifiedEmails>>;
|
||||
};
|
||||
|
||||
function WorkflowPage({
|
||||
workflowData: workflowDataProp,
|
||||
verifiedNumbers: verifiedNumbersProp,
|
||||
verifiedEmails: verifiedEmailsProp,
|
||||
}: PageProps) {
|
||||
const { t, i18n } = useLocale();
|
||||
const session = useSession();
|
||||
const params = useParamsWithFallback();
|
||||
@@ -58,27 +69,36 @@ function WorkflowPage() {
|
||||
const user = userQuery.data;
|
||||
|
||||
const {
|
||||
data: workflow,
|
||||
isError,
|
||||
data: workflowData,
|
||||
isError: _isError,
|
||||
error,
|
||||
isPending: isPendingWorkflow,
|
||||
isPending: _isPendingWorkflow,
|
||||
} = trpc.viewer.workflows.get.useQuery(
|
||||
{ id: +workflowId },
|
||||
{
|
||||
enabled: !!workflowId,
|
||||
enabled: workflowDataProp ? false : !!workflowId,
|
||||
}
|
||||
);
|
||||
|
||||
const { data: verifiedNumbers } = trpc.viewer.workflows.getVerifiedNumbers.useQuery(
|
||||
const workflow = workflowDataProp || workflowData;
|
||||
const isPendingWorkflow = workflowDataProp ? false : _isPendingWorkflow;
|
||||
const isError = workflowDataProp ? false : _isError;
|
||||
|
||||
const { data: verifiedNumbersData } = trpc.viewer.workflows.getVerifiedNumbers.useQuery(
|
||||
{ teamId: workflow?.team?.id },
|
||||
{
|
||||
enabled: !!workflow?.id,
|
||||
enabled: verifiedNumbersProp ? false : !!workflow?.id,
|
||||
}
|
||||
);
|
||||
const verifiedNumbers = verifiedNumbersProp || verifiedNumbersData;
|
||||
|
||||
const { data: verifiedEmails } = trpc.viewer.workflows.getVerifiedEmails.useQuery({
|
||||
teamId: workflow?.team?.id,
|
||||
});
|
||||
const { data: verifiedEmailsData } = trpc.viewer.workflows.getVerifiedEmails.useQuery(
|
||||
{
|
||||
teamId: workflow?.team?.id,
|
||||
},
|
||||
{ enabled: !verifiedEmailsProp }
|
||||
);
|
||||
const verifiedEmails = verifiedEmailsProp || verifiedEmailsData;
|
||||
|
||||
const isOrg = workflow?.team?.isOrganization ?? false;
|
||||
|
||||
@@ -135,7 +155,7 @@ function WorkflowPage() {
|
||||
setSelectedOptions(activeOn || []);
|
||||
} else {
|
||||
setSelectedOptions(
|
||||
workflowData.activeOn.flatMap((active) => {
|
||||
workflowData.activeOn?.flatMap((active) => {
|
||||
if (workflowData.teamId && active.eventType.parentId) return [];
|
||||
return {
|
||||
value: String(active.eventType.id),
|
||||
@@ -152,7 +172,7 @@ function WorkflowPage() {
|
||||
}
|
||||
}
|
||||
//translate dynamic variables into local language
|
||||
const steps = workflowData.steps.map((step) => {
|
||||
const steps = workflowData.steps?.map((step) => {
|
||||
const updatedStep = {
|
||||
...step,
|
||||
senderName: step.sender,
|
||||
@@ -342,7 +362,7 @@ function WorkflowPage() {
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Alert severity="error" title="Something went wrong" message={error.message} />
|
||||
<Alert severity="error" title="Something went wrong" message={error?.message ?? ""} />
|
||||
)}
|
||||
</ShellMain>
|
||||
</Form>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
|
||||
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { MembershipRole } from "@calcom/prisma/client";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import type { TFilteredListInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/filteredList.schema";
|
||||
import type { TGetVerifiedEmailsInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedEmails.schema";
|
||||
import type { TGetVerifiedNumbersInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedNumbers.schema";
|
||||
|
||||
export const ZGetInputSchema = z.object({
|
||||
id: z.number(),
|
||||
@@ -8,6 +15,48 @@ export const ZGetInputSchema = z.object({
|
||||
|
||||
export type TGetInputSchema = z.infer<typeof ZGetInputSchema>;
|
||||
|
||||
const { include: includedFields } = Prisma.validator<Prisma.WorkflowDefaultArgs>()({
|
||||
include: {
|
||||
activeOn: {
|
||||
select: {
|
||||
eventType: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
parentId: true,
|
||||
_count: {
|
||||
select: {
|
||||
children: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
activeOnTeams: {
|
||||
select: {
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
steps: true,
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
name: true,
|
||||
members: true,
|
||||
logoUrl: true,
|
||||
isOrganization: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export class WorkflowRepository {
|
||||
static async getById({ id }: TGetInputSchema) {
|
||||
return await prisma.workflow.findFirst({
|
||||
@@ -50,4 +99,181 @@ export class WorkflowRepository {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static async getVerifiedNumbers({
|
||||
userId,
|
||||
teamId,
|
||||
}: TGetVerifiedNumbersInputSchema & { userId: number | null }) {
|
||||
if (!userId) {
|
||||
throw new Error("User Id not found");
|
||||
}
|
||||
const verifiedNumbers = await prisma.verifiedNumber.findMany({
|
||||
where: {
|
||||
OR: [{ userId }, { teamId }],
|
||||
},
|
||||
});
|
||||
|
||||
return verifiedNumbers;
|
||||
}
|
||||
|
||||
static async getVerifiedEmails({
|
||||
userEmail,
|
||||
userId,
|
||||
teamId,
|
||||
}: TGetVerifiedEmailsInputSchema & { userEmail: string | null; userId: number | null }) {
|
||||
if (!userId) {
|
||||
throw new Error("User Id not found");
|
||||
}
|
||||
if (!userEmail) {
|
||||
throw new Error("User email not found");
|
||||
}
|
||||
|
||||
let verifiedEmails: string[] = [userEmail];
|
||||
|
||||
if (teamId) {
|
||||
const team = await prisma.team.findFirst({
|
||||
where: {
|
||||
id: teamId,
|
||||
},
|
||||
select: {
|
||||
members: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!team) {
|
||||
throw new Error("Team not found");
|
||||
}
|
||||
|
||||
const isTeamMember = team.members.some((member) => member.userId === userId);
|
||||
|
||||
if (!isTeamMember) {
|
||||
throw new Error("You are not a member of this team");
|
||||
}
|
||||
|
||||
verifiedEmails = verifiedEmails.concat(team.members.map((member) => member.user.email));
|
||||
}
|
||||
|
||||
const emails = (
|
||||
await prisma.verifiedEmail.findMany({
|
||||
where: {
|
||||
OR: [{ userId }, { teamId }],
|
||||
},
|
||||
})
|
||||
).map((verifiedEmail) => verifiedEmail.email);
|
||||
|
||||
verifiedEmails = verifiedEmails.concat(emails);
|
||||
|
||||
return verifiedEmails;
|
||||
}
|
||||
|
||||
static async getFilteredList({ userId, input }: { userId?: number; input: TFilteredListInputSchema }) {
|
||||
const filters = input?.filters;
|
||||
|
||||
const filtered = filters && hasFilter(filters);
|
||||
|
||||
const allWorkflows = await prisma.workflow.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
userId,
|
||||
},
|
||||
{
|
||||
team: {
|
||||
members: {
|
||||
some: {
|
||||
userId,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
include: includedFields,
|
||||
orderBy: [
|
||||
{
|
||||
position: "desc",
|
||||
},
|
||||
{
|
||||
id: "asc",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!filtered) {
|
||||
const workflowsWithReadOnly: WorkflowType[] = allWorkflows.map((workflow) => {
|
||||
const readOnly = !!workflow.team?.members?.find(
|
||||
(member) => member.userId === userId && member.role === MembershipRole.MEMBER
|
||||
);
|
||||
|
||||
return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
|
||||
});
|
||||
|
||||
return {
|
||||
filtered: workflowsWithReadOnly,
|
||||
totalCount: allWorkflows.length,
|
||||
};
|
||||
}
|
||||
|
||||
const where = {
|
||||
OR: [] as Prisma.WorkflowWhereInput[],
|
||||
};
|
||||
|
||||
if (filtered) {
|
||||
if (!!filters.teamIds) {
|
||||
where.OR.push({
|
||||
team: {
|
||||
id: {
|
||||
in: filters.teamIds ?? [],
|
||||
},
|
||||
members: {
|
||||
some: {
|
||||
userId,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!!filters.userIds) {
|
||||
where.OR.push({
|
||||
userId: {
|
||||
in: filters.userIds,
|
||||
},
|
||||
teamId: null,
|
||||
});
|
||||
}
|
||||
|
||||
const filteredWorkflows = await prisma.workflow.findMany({
|
||||
where,
|
||||
include: includedFields,
|
||||
orderBy: {
|
||||
id: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
const workflowsWithReadOnly: WorkflowType[] = filteredWorkflows.map((workflow) => {
|
||||
const readOnly = !!workflow.team?.members?.find(
|
||||
(member) => member.userId === userId && member.role === MembershipRole.MEMBER
|
||||
);
|
||||
|
||||
return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
|
||||
});
|
||||
|
||||
return {
|
||||
filtered: workflowsWithReadOnly,
|
||||
totalCount: allWorkflows.length,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
|
||||
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
|
||||
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/client";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import type { TFilteredListInputSchema } from "./filteredList.schema";
|
||||
@@ -58,105 +56,5 @@ const { include: includedFields } = Prisma.validator<Prisma.WorkflowDefaultArgs>
|
||||
});
|
||||
|
||||
export const filteredListHandler = async ({ ctx, input }: FilteredListOptions) => {
|
||||
const { prisma, user } = ctx;
|
||||
|
||||
const filters = input?.filters;
|
||||
|
||||
const filtered = filters && hasFilter(filters);
|
||||
|
||||
const allWorkflows = await prisma.workflow.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
userId: user.id,
|
||||
},
|
||||
{
|
||||
team: {
|
||||
members: {
|
||||
some: {
|
||||
userId: user.id,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
include: includedFields,
|
||||
orderBy: [
|
||||
{
|
||||
position: "desc",
|
||||
},
|
||||
{
|
||||
id: "asc",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!filtered) {
|
||||
const workflowsWithReadOnly: WorkflowType[] = allWorkflows.map((workflow) => {
|
||||
const readOnly = !!workflow.team?.members?.find(
|
||||
(member) => member.userId === ctx.user.id && member.role === MembershipRole.MEMBER
|
||||
);
|
||||
|
||||
return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
|
||||
});
|
||||
|
||||
return {
|
||||
filtered: workflowsWithReadOnly,
|
||||
totalCount: allWorkflows.length,
|
||||
};
|
||||
}
|
||||
|
||||
const where = {
|
||||
OR: [] as Prisma.WorkflowWhereInput[],
|
||||
};
|
||||
|
||||
if (filtered) {
|
||||
if (!!filters.teamIds) {
|
||||
where.OR.push({
|
||||
team: {
|
||||
id: {
|
||||
in: filters.teamIds ?? [],
|
||||
},
|
||||
members: {
|
||||
some: {
|
||||
userId: user.id,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!!filters.userIds) {
|
||||
where.OR.push({
|
||||
userId: {
|
||||
in: filters.userIds,
|
||||
},
|
||||
teamId: null,
|
||||
});
|
||||
}
|
||||
|
||||
const filteredWorkflows = await prisma.workflow.findMany({
|
||||
where,
|
||||
include: includedFields,
|
||||
orderBy: {
|
||||
id: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
const workflowsWithReadOnly: WorkflowType[] = filteredWorkflows.map((workflow) => {
|
||||
const readOnly = !!workflow.team?.members?.find(
|
||||
(member) => member.userId === ctx.user.id && member.role === MembershipRole.MEMBER
|
||||
);
|
||||
|
||||
return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
|
||||
});
|
||||
|
||||
return {
|
||||
filtered: workflowsWithReadOnly,
|
||||
totalCount: allWorkflows.length,
|
||||
};
|
||||
}
|
||||
return await WorkflowRepository.getFilteredList({ userId: ctx.user.id, input });
|
||||
};
|
||||
@@ -1,8 +1,6 @@
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import type { TGetVerifiedEmailsInputSchema } from "./getVerifiedEmails.schema";
|
||||
|
||||
type GetVerifiedEmailsOptions = {
|
||||
@@ -13,51 +11,9 @@ type GetVerifiedEmailsOptions = {
|
||||
};
|
||||
|
||||
export const getVerifiedEmailsHandler = async ({ ctx, input }: GetVerifiedEmailsOptions) => {
|
||||
const { user } = ctx;
|
||||
const { teamId } = input;
|
||||
let verifiedEmails: string[] = [user.email];
|
||||
|
||||
if (teamId) {
|
||||
const team = await prisma.team.findFirst({
|
||||
where: {
|
||||
id: teamId,
|
||||
},
|
||||
select: {
|
||||
members: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!team) {
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: "Team not found" });
|
||||
}
|
||||
|
||||
const isTeamMember = team.members.some((member) => member.userId === user.id);
|
||||
|
||||
if (!isTeamMember) {
|
||||
throw new TRPCError({ code: "FORBIDDEN", message: "You are not a member of this team" });
|
||||
}
|
||||
|
||||
verifiedEmails = verifiedEmails.concat(team.members.map((member) => member.user.email));
|
||||
}
|
||||
|
||||
const emails = (
|
||||
await prisma.verifiedEmail.findMany({
|
||||
where: {
|
||||
OR: [{ userId: user.id }, { teamId: input.teamId }],
|
||||
},
|
||||
})
|
||||
).map((verifiedEmail) => verifiedEmail.email);
|
||||
|
||||
verifiedEmails = verifiedEmails.concat(emails);
|
||||
|
||||
return verifiedEmails;
|
||||
return await WorkflowRepository.getVerifiedEmails({
|
||||
userId: ctx.user.id,
|
||||
userEmail: ctx.user.email,
|
||||
teamId: input.teamId,
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import type { TGetVerifiedNumbersInputSchema } from "./getVerifiedNumbers.schema";
|
||||
@@ -11,12 +11,8 @@ type GetVerifiedNumbersOptions = {
|
||||
};
|
||||
|
||||
export const getVerifiedNumbersHandler = async ({ ctx, input }: GetVerifiedNumbersOptions) => {
|
||||
const { user } = ctx;
|
||||
const verifiedNumbers = await prisma.verifiedNumber.findMany({
|
||||
where: {
|
||||
OR: [{ userId: user.id }, { teamId: input.teamId }],
|
||||
},
|
||||
return await WorkflowRepository.getVerifiedNumbers({
|
||||
userId: ctx.user.id,
|
||||
teamId: input.teamId,
|
||||
});
|
||||
|
||||
return verifiedNumbers;
|
||||
};
|
||||
Reference in new issue
Block a user