Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 8 additions & 27 deletions apps/web/app/api/outlook/linking/callback/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,18 @@ export const GET = withError("outlook/linking/callback", async (request) => {
}

const profile = await profileResponse.json();
const providerAccountId = profile.id;
const providerEmail = profile.mail || profile.userPrincipalName;

if (!providerEmail) {
throw new Error("Profile missing required email");
if (!providerAccountId || !providerEmail) {
throw new Error("Profile missing required id or email");
}

const existingAccountByProviderId = await prisma.account.findUnique({
const existingAccount = await prisma.account.findUnique({
where: {
provider_providerAccountId: {
provider: "microsoft",
providerAccountId: profile.id || providerEmail,
providerAccountId,
},
},
select: {
Expand All @@ -134,24 +135,6 @@ export const GET = withError("outlook/linking/callback", async (request) => {
},
});

const existingAccountByEmail = await prisma.account.findFirst({
where: {
provider: "microsoft",
user: {
email: providerEmail.trim().toLowerCase(),
},
},
select: {
id: true,
userId: true,
user: { select: { name: true, email: true } },
emailAccount: true,
},
});

const existingAccount =
existingAccountByProviderId || existingAccountByEmail;

const linkingResult = await handleAccountLinking({
existingAccountId: existingAccount?.id || null,
hasEmailAccount: !!existingAccount?.emailAccount,
Expand Down Expand Up @@ -207,15 +190,13 @@ export const GET = withError("outlook/linking/callback", async (request) => {
logger.warn("Failed to fetch profile picture", { error });
}

const microsoftProviderAccountId = profile.id || providerEmail;

try {
const newAccount = await prisma.account.create({
data: {
userId: targetUserId,
type: "oidc",
provider: "microsoft",
providerAccountId: microsoftProviderAccountId,
providerAccountId,
access_token: tokens.access_token,
refresh_token: tokens.refresh_token,
expires_at: expiresAt,
Expand Down Expand Up @@ -247,7 +228,7 @@ export const GET = withError("outlook/linking/callback", async (request) => {
where: {
provider_providerAccountId: {
provider: "microsoft",
providerAccountId: microsoftProviderAccountId,
providerAccountId,
},
},
select: { userId: true },
Expand All @@ -258,7 +239,7 @@ export const GET = withError("outlook/linking/callback", async (request) => {
"Account was created by concurrent request, continuing",
{
targetUserId,
providerAccountId: microsoftProviderAccountId,
providerAccountId,
},
);
} else {
Expand Down
9 changes: 5 additions & 4 deletions apps/web/app/api/resend/summary/all/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { captureException } from "@/utils/error";
import type { Logger } from "@/utils/logger";
import { publishToQstashQueue } from "@/utils/upstash";
import { getPremiumUserFilter } from "@/utils/premium";
import type { SendSummaryEmailBody } from "../validation";

export const dynamic = "force-dynamic";
export const maxDuration = 300;
Expand Down Expand Up @@ -45,7 +46,7 @@ async function sendSummaryAllUpdate(logger: Logger) {
logger.info("Sending summary all update");

const emailAccounts = await prisma.emailAccount.findMany({
select: { email: true },
select: { id: true },
where: {
summaryEmailFrequency: {
not: Frequency.NEVER,
Expand All @@ -64,16 +65,16 @@ async function sendSummaryAllUpdate(logger: Logger) {

for (const emailAccount of emailAccounts) {
try {
await publishToQstashQueue({
await publishToQstashQueue<SendSummaryEmailBody>({
queueName: "email-summary-all",
parallelism: 3, // Allow up to 3 concurrent jobs from this queue
url,
body: { email: emailAccount.email },
body: { emailAccountId: emailAccount.id },
headers: getCronSecretHeader(),
});
} catch (error) {
logger.error("Failed to publish to Qstash", {
email: emailAccount.email,
emailAccountId: emailAccount.id,
error,
});
}
Expand Down
4 changes: 1 addition & 3 deletions apps/web/app/api/resend/summary/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { z } from "zod";
import { NextResponse } from "next/server";
import { subHours } from "date-fns/subHours";
import { sendSummaryEmail } from "@inboxzero/resend";
Expand All @@ -12,11 +11,10 @@ import type { Logger } from "@/utils/logger";
import { getMessagesBatch } from "@/utils/gmail/message";
import { decodeSnippet } from "@/utils/gmail/decode";
import { createUnsubscribeToken } from "@/utils/unsubscribe";
import { sendSummaryEmailBody } from "./validation";

export const maxDuration = 60;

const sendSummaryEmailBody = z.object({ emailAccountId: z.string() });

export const GET = withEmailAccount("resend/summary", async (request) => {
// send to self
const emailAccountId = request.auth.emailAccountId;
Expand Down
7 changes: 7 additions & 0 deletions apps/web/app/api/resend/summary/validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from "zod";

export const sendSummaryEmailBody = z.object({
emailAccountId: z.string(),
});

export type SendSummaryEmailBody = z.infer<typeof sendSummaryEmailBody>;
Loading