Files
calendar/packages/lib/checkRateLimitAndThrowError.ts
T
883d745784 feat: SMS/Whatsapp to attendee for teams (#14648)
* remove event type requires confirmation

* allow sms sending also for team (frontend)

* allow text to attendee for team (backend)

* add rate limiting for SMS (WIP)

* add functionality to lock and unlock SMS sending (+admin UI view)

* rename to smsLockState

* add ability to lock users and teams

* don't send sms if locked

* add missing imports

* fix rate limit namespace

* add translation

* fix type error

* remove prop from UsersTable

* add smsLockState to buildUser

* code clean up

* create seperate sms rate limit function

* fix type error

* add missing userId and teamId to sendSMS

* code improvements

* add User Team type

* fix marking as reviewed

* check monthly sms limit only for user

* don't lock orgs

* fix type error

* fix avatars

* fix type error

* fix type error

* fix type error

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-04-23 19:48:44 +00:00

80 lines
2.0 KiB
TypeScript

import prisma from "@calcom/prisma";
import { SMSLockState } from "@calcom/prisma/enums";
import { TRPCError } from "@calcom/trpc/server";
import type { RateLimitHelper } from "./rateLimit";
import { rateLimiter } from "./rateLimit";
export async function checkRateLimitAndThrowError({
rateLimitingType = "core",
identifier,
onRateLimiterResponse,
opts,
}: RateLimitHelper) {
const response = await rateLimiter()({ rateLimitingType, identifier, opts });
const { success, reset } = response;
if (onRateLimiterResponse) onRateLimiterResponse(response);
if (!success) {
const convertToSeconds = (ms: number) => Math.floor(ms / 1000);
const secondsToWait = convertToSeconds(reset - Date.now());
throw new TRPCError({
code: "TOO_MANY_REQUESTS",
message: `Rate limit exceeded. Try again in ${secondsToWait} seconds.`,
});
}
}
export async function checkSMSRateLimit({
rateLimitingType = "sms",
identifier,
onRateLimiterResponse,
opts,
}: RateLimitHelper) {
const response = await rateLimiter()({ rateLimitingType, identifier, opts });
const { success } = response;
if (onRateLimiterResponse) onRateLimiterResponse(response);
if (!success) {
await changeSMSLockState(
identifier,
rateLimitingType === "sms" ? SMSLockState.LOCKED : SMSLockState.REVIEW_NEEDED
);
}
}
async function changeSMSLockState(identifier: string, status: SMSLockState) {
let userId, teamId;
if (identifier.startsWith("sms:user:")) {
userId = Number(identifier.slice(9));
} else if (identifier.startsWith("sms:team:")) {
teamId = Number(identifier.slice(9));
}
if (userId) {
await prisma.user.update({
where: {
id: userId,
profiles: { none: {} },
},
data: {
smsLockState: status,
},
});
} else {
await prisma.team.update({
where: {
id: teamId,
parentId: null,
isOrganization: false,
},
data: {
smsLockState: status,
},
});
}
}