Compare commits
117
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55df0e3c9d | ||
|
|
730aab3e3d | ||
|
|
63740c02c7 | ||
|
|
c5942bcfcd | ||
|
|
c4547c51a2 | ||
|
|
cf89046ede | ||
|
|
d5d44fb64b | ||
|
|
4bb092c345 | ||
|
|
e1f7e94e36 | ||
|
|
2e9d5f7df1 | ||
|
|
8c943e8817 | ||
|
|
56821553fe | ||
|
|
b512ceb217 | ||
|
|
cfeb18de3f | ||
|
|
b407be933d | ||
|
|
4e1920471d | ||
|
|
6ee752aed8 | ||
|
|
a1922efab5 | ||
|
|
76332a759b | ||
|
|
dfdda8a5b8 | ||
|
|
286ee6b1bd | ||
|
|
ef8b0fa41c | ||
|
|
7fbeeae25b | ||
|
|
5cf0553199 | ||
|
|
4f114ef8d3 | ||
|
|
a9d6fbd14d | ||
|
|
3e1629add9 | ||
|
|
f1ac0642d1 | ||
|
|
4689775a1f | ||
|
|
4011733271 | ||
|
|
f41aa234d7 | ||
|
|
a44a3e5b84 | ||
|
|
98a075d062 | ||
|
|
bdc3cb9d6e | ||
|
|
616e4c4908 | ||
|
|
eaf695824b | ||
|
|
69a76f7fb7 | ||
|
|
d70fa46260 | ||
|
|
efba58a36a | ||
|
|
b3a28dca25 | ||
|
|
3b471f0e25 | ||
|
|
aac5fa3537 | ||
|
|
134f7e591e | ||
|
|
5bb2bc3ba4 | ||
|
|
bb6f5cca93 | ||
|
|
81bd8033a9 | ||
|
|
c2a44e9319 | ||
|
|
39917ebfa6 | ||
|
|
9ee06b410e | ||
|
|
76ced2d3b8 | ||
|
|
eaa1ad6578 | ||
|
|
f9095d298d | ||
|
|
fd87954048 | ||
|
|
be249a94de | ||
|
|
59582cf8f5 | ||
|
|
5c70060992 | ||
|
|
ae7f8f1653 | ||
|
|
4d0458b0e8 | ||
|
|
55e6682832 | ||
|
|
65448c017f | ||
|
|
e9fd23d0d3 | ||
|
|
badc857bcd | ||
|
|
7fe80dd3dd | ||
|
|
5feca13cfb | ||
|
|
f267cd9cd9 | ||
|
|
e8c2d4fa95 | ||
|
|
7e415b4542 | ||
|
|
43f4caaba4 | ||
|
|
0c2ba81269 | ||
|
|
3aca339c95 | ||
|
|
41553f6c01 | ||
|
|
3661860433 | ||
|
|
f0210d06ea | ||
|
|
fcfb8cc9a3 | ||
|
|
88391c7942 | ||
|
|
e9c6af562e | ||
|
|
18bac4a063 | ||
|
|
0332118724 | ||
|
|
34b62f7516 | ||
|
|
da1863069d | ||
|
|
31270ca86b | ||
|
|
7e876e3457 | ||
|
|
cbfd991ab7 | ||
|
|
d7cd185da1 | ||
|
|
416504240c | ||
|
|
cfadd2e892 | ||
|
|
3aab13b4da | ||
|
|
76bba1ca05 | ||
|
|
06fcea4116 | ||
|
|
a7fecaf578 | ||
|
|
639940d1bf | ||
|
|
d7397d4563 | ||
|
|
cf07621de7 | ||
|
|
110615b509 | ||
|
|
3915348d03 | ||
|
|
5230694e2c | ||
|
|
68f2fc9174 | ||
|
|
a63802dea7 | ||
|
|
2be388373f | ||
|
|
a62c74f79e | ||
|
|
1a8b5d145f | ||
|
|
794c99239a | ||
|
|
1fee90322d | ||
|
|
ee70111c45 | ||
|
|
79169de8d8 | ||
|
|
74288b0ecb | ||
|
|
a977fb4970 | ||
|
|
79a09362c9 | ||
|
|
94a50086e6 | ||
|
|
18ba54522c | ||
|
|
5483597a5b | ||
|
|
4ed0901957 | ||
|
|
dbbf3ae2a2 | ||
|
|
c3985e3efb | ||
|
|
c28eb90928 | ||
|
|
a55d56f260 | ||
|
|
1d25265c56 |
@@ -319,6 +319,55 @@ dates.map((date) => dayjs.utc(date).add(1, "day").format());
|
|||||||
dates.map((date) => new Date(date.valueOf() + 24 * 60 * 60 * 1000));
|
dates.map((date) => new Date(date.valueOf() + 24 * 60 * 60 * 1000));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Next.js App Directory: Authorisation Checks in Pages
|
||||||
|
|
||||||
|
This can include checking session.user exists or session.org etc.
|
||||||
|
|
||||||
|
### TL;DR:
|
||||||
|
|
||||||
|
Don’t put permission checks in layout.tsx! Always put them directly inside your page.tsx or relevant server components for every restricted route.
|
||||||
|
|
||||||
|
|
||||||
|
### Why Not to Use Layouts for Permission Checks
|
||||||
|
|
||||||
|
* Layouts don’t intercept all requests: If a user navigates directly or refreshes a protected route, layout checks might be skipped, exposing sensitive content.
|
||||||
|
* APIs and server actions bypass layouts: Sensitive operations running on the server can’t be guarded by checks in the layout.
|
||||||
|
* Risk of data leaks: Only page/server-level checks ensure that unauthorized users never get protected data.
|
||||||
|
|
||||||
|
### ✅ How To Secure Routes (The Right Way)
|
||||||
|
|
||||||
|
* Check permissions inside page.tsx or the actual server component.
|
||||||
|
* Perform all session/user/role validation before querying or rendering sensitive content.
|
||||||
|
* Redirect or return nothing to unauthorized users, before running restricted code.
|
||||||
|
|
||||||
|
### 🛠️ Example: Page-Level Permission Check
|
||||||
|
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// app/admin/page.tsx
|
||||||
|
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { getUserSession } from "@/lib/auth";
|
||||||
|
|
||||||
|
export default async function AdminPage() {
|
||||||
|
const session = await getUserSession();
|
||||||
|
|
||||||
|
if (!session || session.user.role !== "admin") {
|
||||||
|
redirect("/"); // Or show an error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected content here
|
||||||
|
return <div>Welcome, Admin!</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🧠 Key Reminders
|
||||||
|
|
||||||
|
* Put permission guards in every restricted page.tsx.
|
||||||
|
* Never assume layouts are secure for guarding data.
|
||||||
|
* Validate users before any sensitive queries or rendering.
|
||||||
|
|
||||||
|
|
||||||
## Avoid using Dayjs if you don’t need to be strictly tz aware.
|
## Avoid using Dayjs if you don’t need to be strictly tz aware.
|
||||||
|
|
||||||
When doing logic like Dayjs.startOf(".."), you can instead use date-fns' `startOfMonth(dateObj)` / `endOfDay(dateObj)`;
|
When doing logic like Dayjs.startOf(".."), you can instead use date-fns' `startOfMonth(dateObj)` / `endOfDay(dateObj)`;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"access": "public",
|
"access": "public",
|
||||||
"baseBranch": "main",
|
"baseBranch": "main",
|
||||||
"updateInternalDependencies": "patch",
|
"updateInternalDependencies": "patch",
|
||||||
"ignore": ["@calcom/platform-libraries"],
|
"ignore": ["@calcom/platform-libraries", "@calcom/api-v2"],
|
||||||
"privatePackages": {
|
"privatePackages": {
|
||||||
"version": false,
|
"version": false,
|
||||||
"tag": false
|
"tag": false
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN=0
|
|||||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE=
|
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE=
|
||||||
STRIPE_TEAM_MONTHLY_PRICE_ID=
|
STRIPE_TEAM_MONTHLY_PRICE_ID=
|
||||||
NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID=
|
NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID=
|
||||||
|
ORG_MONTHLY_CREDITS=
|
||||||
STRIPE_TEAM_PRODUCT_ID=
|
STRIPE_TEAM_PRODUCT_ID=
|
||||||
# It is a price ID in the product with id STRIPE_ORG_PRODUCT_ID
|
# It is a price ID in the product with id STRIPE_ORG_PRODUCT_ID
|
||||||
STRIPE_ORG_MONTHLY_PRICE_ID=
|
STRIPE_ORG_MONTHLY_PRICE_ID=
|
||||||
|
|||||||
+87
-7
@@ -1,4 +1,3 @@
|
|||||||
// This configuration only applies to the package manager root.
|
|
||||||
/** @type {import("eslint").Linter.Config} */
|
/** @type {import("eslint").Linter.Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ["./packages/config/eslint-preset.js"],
|
extends: ["./packages/config/eslint-preset.js"],
|
||||||
@@ -7,26 +6,107 @@ module.exports = {
|
|||||||
"import/no-cycle": ["warn", { maxDepth: Infinity }],
|
"import/no-cycle": ["warn", { maxDepth: Infinity }],
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
|
// WARN: features must not be imported by app-store or lib
|
||||||
{
|
{
|
||||||
files: ["packages/lib/**/*.{ts,tsx,js,jsx}", "packages/prisma/**/*.{ts,tsx,js,jsx}"],
|
files: ["packages/app-store/**/*.{ts,tsx,js,jsx}", "packages/lib/**/*.{ts,tsx,js,jsx}"],
|
||||||
rules: {
|
rules: {
|
||||||
"no-restricted-imports": [
|
"no-restricted-imports": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
paths: ["@calcom/app-store"],
|
patterns: [
|
||||||
patterns: ["@calcom/app-store/*"],
|
{
|
||||||
|
group: [
|
||||||
|
// Catch all relative paths into features
|
||||||
|
"**/features",
|
||||||
|
"**/features/*",
|
||||||
|
// Catch all alias imports
|
||||||
|
"@calcom/features",
|
||||||
|
"@calcom/features/*",
|
||||||
|
],
|
||||||
|
message: "Avoid importing @calcom/features from @calcom/app-store or @calcom/lib.",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// WARN: lib must not import app-store or features
|
||||||
{
|
{
|
||||||
files: ["packages/app-store/**/*.{ts,tsx,js,jsx}"],
|
files: ["packages/lib/**/*.{ts,tsx,js,jsx}"],
|
||||||
rules: {
|
rules: {
|
||||||
"no-restricted-imports": [
|
"no-restricted-imports": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
paths: ["@calcom/trpc"],
|
patterns: [
|
||||||
patterns: ["@calcom/trpc/*"],
|
{
|
||||||
|
group: [
|
||||||
|
// Catch all relative paths into app-store
|
||||||
|
"**/app-store",
|
||||||
|
"**/app-store/*",
|
||||||
|
// Catch all relative paths into features
|
||||||
|
"**/features",
|
||||||
|
"**/features/*",
|
||||||
|
// Catch alias imports
|
||||||
|
"@calcom/app-store",
|
||||||
|
"@calcom/app-store/*",
|
||||||
|
"@calcom/features",
|
||||||
|
"@calcom/features/*",
|
||||||
|
],
|
||||||
|
message: "@calcom/lib should not import @calcom/app-store or @calcom/features.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ERROR: app-store must not import trpc
|
||||||
|
{
|
||||||
|
files: ["packages/app-store/**/*.{ts,tsx,js,jsx}"],
|
||||||
|
rules: {
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
group: [
|
||||||
|
// Catch all relative paths into trpc
|
||||||
|
"**/trpc",
|
||||||
|
"**/trpc/*",
|
||||||
|
// Catch alias imports
|
||||||
|
"@calcom/trpc",
|
||||||
|
"@calcom/trpc/*",
|
||||||
|
"@trpc",
|
||||||
|
"@trpc/*",
|
||||||
|
],
|
||||||
|
message:
|
||||||
|
"@calcom/app-store must not import trpc. Move UI to apps/web/components/apps or introduce an API boundary.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ERROR: prisma must not import `features` package
|
||||||
|
{
|
||||||
|
files: ["packages/prisma/**/*.{ts,tsx,js,jsx}"],
|
||||||
|
rules: {
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
group: [
|
||||||
|
// Catch all relative paths into features
|
||||||
|
"**/features",
|
||||||
|
"**/features/*",
|
||||||
|
// Catch all alias imports
|
||||||
|
"@calcom/features",
|
||||||
|
"@calcom/features/*",
|
||||||
|
],
|
||||||
|
message: "Avoid importing @calcom/features from @calcom/prisma.",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ jobs:
|
|||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
working-directory: apps/api/v2
|
working-directory: apps/api/v2
|
||||||
run: |
|
run: |
|
||||||
yarn test:e2e
|
yarn workspace @calcom/platform-libraries build && yarn test:e2e
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
echo "yarn test:e2e command exit code: $EXIT_CODE"
|
echo "yarn workspace @calcom/platform-libraries build && yarn test:e2e command exit code: $EXIT_CODE"
|
||||||
exit $EXIT_CODE
|
exit $EXIT_CODE
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ env:
|
|||||||
ATOMS_E2E_API_URL: ${{ secrets.ATOMS_E2E_API_URL }}
|
ATOMS_E2E_API_URL: ${{ secrets.ATOMS_E2E_API_URL }}
|
||||||
ATOMS_E2E_ORG_ID: ${{ secrets.ATOMS_E2E_ORG_ID }}
|
ATOMS_E2E_ORG_ID: ${{ secrets.ATOMS_E2E_ORG_ID }}
|
||||||
ATOMS_E2E_OAUTH_CLIENT_ID_BOOKER_EMBED: ${{ secrets.ATOMS_E2E_OAUTH_CLIENT_ID_BOOKER_EMBED }}
|
ATOMS_E2E_OAUTH_CLIENT_ID_BOOKER_EMBED: ${{ secrets.ATOMS_E2E_OAUTH_CLIENT_ID_BOOKER_EMBED }}
|
||||||
|
ATOMS_E2E_APPLE_ID: ${{ secrets.ATOMS_E2E_APPLE_ID }}
|
||||||
|
ATOMS_E2E_APPLE_CONNECT_APP_SPECIFIC_PASSCODE: ${{ secrets.ATOMS_E2E_APPLE_CONNECT_APP_SPECIFIC_PASSCODE }}
|
||||||
DATABASE_DIRECT_URL: ${{ secrets.CI_DATABASE_URL }}
|
DATABASE_DIRECT_URL: ${{ secrets.CI_DATABASE_URL }}
|
||||||
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
|
||||||
|
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ jobs:
|
|||||||
working-directory: apps/api/v2
|
working-directory: apps/api/v2
|
||||||
run: |
|
run: |
|
||||||
export NODE_OPTIONS="--max_old_space_size=8192"
|
export NODE_OPTIONS="--max_old_space_size=8192"
|
||||||
yarn test
|
yarn workspace @calcom/platform-libraries build && yarn test
|
||||||
|
|||||||
+2
-1
@@ -66,7 +66,8 @@ tsconfig.tsbuildinfo
|
|||||||
.turbo
|
.turbo
|
||||||
|
|
||||||
# Prisma generated files
|
# Prisma generated files
|
||||||
packages/prisma/zod/*.ts
|
packages/prisma/client/*
|
||||||
|
packages/prisma/zod/**/*.ts
|
||||||
packages/prisma/enums
|
packages/prisma/enums
|
||||||
|
|
||||||
# Builds
|
# Builds
|
||||||
|
|||||||
Vendored
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
undecided:
|
||||||
|
- calcom-monorepo
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
undecided:
|
||||||
|
- calcom-monorepo
|
||||||
|
- "@calcom/app-store"
|
||||||
Vendored
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
undecided:
|
||||||
|
- calcom-monorepo
|
||||||
|
- "@calcom/prisma"
|
||||||
@@ -13,6 +13,16 @@
|
|||||||
- `yarn test <filename> -- --integrationTestsOnly` - Run integration tests
|
- `yarn test <filename> -- --integrationTestsOnly` - Run integration tests
|
||||||
- `yarn e2e <filename> --grep "<testName>"` - Run specific E2E test
|
- `yarn e2e <filename> --grep "<testName>"` - Run specific E2E test
|
||||||
|
|
||||||
|
## Tool Preferences
|
||||||
|
|
||||||
|
### Search Tools Priority
|
||||||
|
|
||||||
|
Use tools in this order of preference:
|
||||||
|
|
||||||
|
1. **ast-grep** - For AST-based code searches (if available)
|
||||||
|
2. **rg (ripgrep)** - For fast text searches
|
||||||
|
3. **grep** - As fallback for text searches
|
||||||
|
|
||||||
## 📚 Detailed Documentation
|
## 📚 Detailed Documentation
|
||||||
|
|
||||||
- **[.agents/README.md](.agents/README.md)** - Complete development guide
|
- **[.agents/README.md](.agents/README.md)** - Complete development guide
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
import { captureException as SentryCaptureException } from "@sentry/nextjs";
|
import { captureException as SentryCaptureException } from "@sentry/nextjs";
|
||||||
import type { NextMiddleware } from "next-api-middleware";
|
import type { NextMiddleware } from "next-api-middleware";
|
||||||
|
|
||||||
import { redactError } from "@calcom/lib/redactError";
|
|
||||||
|
|
||||||
export const captureErrors: NextMiddleware = async (_req, res, next) => {
|
export const captureErrors: NextMiddleware = async (_req, res, next) => {
|
||||||
try {
|
try {
|
||||||
// Catch any errors that are thrown in remaining
|
// Catch any errors that are thrown in remaining
|
||||||
// middleware and the API route handler
|
// middleware and the API route handler
|
||||||
await next();
|
await next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
SentryCaptureException(error);
|
SentryCaptureException(error);
|
||||||
const redactedError = redactError(error);
|
res.status(500).json({ message: "Something went wrong" });
|
||||||
if (redactedError instanceof Error) {
|
|
||||||
res.status(400).json({ message: redactedError.message, error: redactedError });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.status(400).json({ message: "Something went wrong", error });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
query: {},
|
query: {},
|
||||||
userId: testUserId,
|
userId: testUserId,
|
||||||
});
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(res._getStatusCode()).toBe(401);
|
expect(res._getStatusCode()).toBe(401);
|
||||||
@@ -43,7 +43,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
query: { apiKey: "test-key" },
|
query: { apiKey: "test-key" },
|
||||||
userId: testUserId,
|
userId: testUserId,
|
||||||
});
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(checkRateLimitAndThrowError as any).mockResolvedValueOnce({
|
(checkRateLimitAndThrowError as any).mockResolvedValueOnce({
|
||||||
limit: 100,
|
limit: 100,
|
||||||
remaining: 99,
|
remaining: 99,
|
||||||
@@ -51,6 +51,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(checkRateLimitAndThrowError).toHaveBeenCalledWith({
|
expect(checkRateLimitAndThrowError).toHaveBeenCalledWith({
|
||||||
@@ -74,15 +75,14 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
// @ts-ignore
|
|
||||||
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
||||||
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
||||||
onRateLimiterResponse(rateLimiterResponse);
|
onRateLimiterResponse(rateLimiterResponse);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(res.getHeader("X-RateLimit-Limit")).toBe(rateLimiterResponse.limit);
|
expect(res.getHeader("X-RateLimit-Limit")).toBe(rateLimiterResponse.limit);
|
||||||
@@ -96,10 +96,11 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
query: { apiKey: "test-key" },
|
query: { apiKey: "test-key" },
|
||||||
userId: testUserId,
|
userId: testUserId,
|
||||||
});
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(checkRateLimitAndThrowError as any).mockRejectedValue(new Error("Rate limit exceeded"));
|
(checkRateLimitAndThrowError as any).mockRejectedValue(new Error("Rate limit exceeded"));
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(res._getStatusCode()).toBe(429);
|
expect(res._getStatusCode()).toBe(429);
|
||||||
@@ -121,6 +122,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
||||||
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
||||||
onRateLimiterResponse(rateLimiterResponse);
|
onRateLimiterResponse(rateLimiterResponse);
|
||||||
@@ -131,6 +133,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
vi.mocked(handleAutoLock).mockResolvedValueOnce(true);
|
vi.mocked(handleAutoLock).mockResolvedValueOnce(true);
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(handleAutoLock).toHaveBeenCalledWith({
|
expect(handleAutoLock).toHaveBeenCalledWith({
|
||||||
@@ -158,6 +161,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
||||||
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
||||||
onRateLimiterResponse(rateLimiterResponse);
|
onRateLimiterResponse(rateLimiterResponse);
|
||||||
@@ -168,6 +172,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
vi.mocked(handleAutoLock).mockRejectedValueOnce(new Error("No user found for this API key."));
|
vi.mocked(handleAutoLock).mockRejectedValueOnce(new Error("No user found for this API key."));
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(handleAutoLock).toHaveBeenCalledWith({
|
expect(handleAutoLock).toHaveBeenCalledWith({
|
||||||
@@ -195,6 +200,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
// Mock rate limiter to trigger the onRateLimiterResponse callback
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
(checkRateLimitAndThrowError as any).mockImplementationOnce(
|
||||||
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
({ onRateLimiterResponse }: { onRateLimiterResponse: (response: RatelimitResponse) => void }) => {
|
||||||
onRateLimiterResponse(rateLimiterResponse);
|
onRateLimiterResponse(rateLimiterResponse);
|
||||||
@@ -235,6 +241,7 @@ describe("rateLimitApiKey middleware", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// @ts-expect-error weird typing between middleware and createMocks
|
// @ts-expect-error weird typing between middleware and createMocks
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
await rateLimitApiKey(req, res, vi.fn() as any);
|
await rateLimitApiKey(req, res, vi.fn() as any);
|
||||||
|
|
||||||
expect(res._getStatusCode()).toBe(429);
|
expect(res._getStatusCode()).toBe(429);
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
|
export const eventTypeSelect = {
|
||||||
|
id: true,
|
||||||
|
title: true,
|
||||||
|
slug: true,
|
||||||
|
length: true,
|
||||||
|
hidden: true,
|
||||||
|
position: true,
|
||||||
|
userId: true,
|
||||||
|
teamId: true,
|
||||||
|
scheduleId: true,
|
||||||
|
eventName: true,
|
||||||
|
timeZone: true,
|
||||||
|
periodType: true,
|
||||||
|
periodStartDate: true,
|
||||||
|
periodEndDate: true,
|
||||||
|
periodDays: true,
|
||||||
|
periodCountCalendarDays: true,
|
||||||
|
requiresConfirmation: true,
|
||||||
|
recurringEvent: true,
|
||||||
|
disableGuests: true,
|
||||||
|
hideCalendarNotes: true,
|
||||||
|
minimumBookingNotice: true,
|
||||||
|
beforeEventBuffer: true,
|
||||||
|
afterEventBuffer: true,
|
||||||
|
schedulingType: true,
|
||||||
|
price: true,
|
||||||
|
currency: true,
|
||||||
|
slotInterval: true,
|
||||||
|
parentId: true,
|
||||||
|
successRedirectUrl: true,
|
||||||
|
description: true,
|
||||||
|
locations: true,
|
||||||
|
metadata: true,
|
||||||
|
seatsPerTimeSlot: true,
|
||||||
|
seatsShowAttendees: true,
|
||||||
|
seatsShowAvailabilityCount: true,
|
||||||
|
bookingFields: true,
|
||||||
|
bookingLimits: true,
|
||||||
|
onlyShowFirstAvailableSlot: true,
|
||||||
|
durationLimits: true,
|
||||||
|
customInputs: {
|
||||||
|
select: { id: true, label: true, required: true, options: true, type: true, placeholder: true },
|
||||||
|
},
|
||||||
|
hashedLink: {
|
||||||
|
select: { link: true },
|
||||||
|
},
|
||||||
|
team: {
|
||||||
|
select: { slug: true },
|
||||||
|
},
|
||||||
|
hosts: {
|
||||||
|
select: {
|
||||||
|
userId: true,
|
||||||
|
isFixed: true,
|
||||||
|
scheduleId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
select: { username: true, id: true },
|
||||||
|
},
|
||||||
|
children: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
userId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies Prisma.EventTypeSelect;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod";
|
import { ApiKeySchema as ApiKey } from "@calcom/prisma/zod/modelSchema/ApiKeySchema";
|
||||||
|
|
||||||
export const apiKeyCreateBodySchema = ApiKey.pick({
|
export const apiKeyCreateBodySchema = ApiKey.pick({
|
||||||
note: true,
|
note: true,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||||
import { _AttendeeModel as Attendee } from "@calcom/prisma/zod";
|
import { AttendeeSchema } from "@calcom/prisma/zod/modelSchema/AttendeeSchema";
|
||||||
|
|
||||||
import { timeZone } from "~/lib/validations/shared/timeZone";
|
import { timeZone } from "~/lib/validations/shared/timeZone";
|
||||||
|
|
||||||
export const schemaAttendeeBaseBodyParams = Attendee.pick({
|
export const schemaAttendeeBaseBodyParams = AttendeeSchema.pick({
|
||||||
bookingId: true,
|
bookingId: true,
|
||||||
email: true,
|
email: true,
|
||||||
name: true,
|
name: true,
|
||||||
@@ -31,7 +31,7 @@ const schemaAttendeeEditParams = z
|
|||||||
export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeEditParams);
|
export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeEditParams);
|
||||||
export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeCreateParams);
|
export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeCreateParams);
|
||||||
|
|
||||||
export const schemaAttendeeReadPublic = Attendee.pick({
|
export const schemaAttendeeReadPublic = AttendeeSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
bookingId: true,
|
bookingId: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { _AvailabilityModel as Availability, _ScheduleModel as Schedule } from "@calcom/prisma/zod";
|
|
||||||
import { denullishShape } from "@calcom/prisma/zod-utils";
|
import { denullishShape } from "@calcom/prisma/zod-utils";
|
||||||
|
import { AvailabilitySchema } from "@calcom/prisma/zod/modelSchema/AvailabilitySchema";
|
||||||
|
import { ScheduleSchema } from "@calcom/prisma/zod/modelSchema/ScheduleSchema";
|
||||||
|
|
||||||
export const schemaAvailabilityBaseBodyParams = /** We make all these properties required */ denullishShape(
|
export const schemaAvailabilityBaseBodyParams = /** We make all these properties required */ denullishShape(
|
||||||
Availability.pick({
|
AvailabilitySchema.pick({
|
||||||
/** We need to pass the schedule where this availability belongs to */
|
/** We need to pass the schedule where this availability belongs to */
|
||||||
scheduleId: true,
|
scheduleId: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const schemaAvailabilityReadPublic = Availability.pick({
|
export const schemaAvailabilityReadPublic = AvailabilitySchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
startTime: true,
|
startTime: true,
|
||||||
endTime: true,
|
endTime: true,
|
||||||
@@ -19,7 +20,7 @@ export const schemaAvailabilityReadPublic = Availability.pick({
|
|||||||
days: true,
|
days: true,
|
||||||
// eventTypeId: true /** @deprecated */,
|
// eventTypeId: true /** @deprecated */,
|
||||||
// userId: true /** @deprecated */,
|
// userId: true /** @deprecated */,
|
||||||
}).merge(z.object({ success: z.boolean().optional(), Schedule: Schedule.partial() }).partial());
|
}).merge(z.object({ success: z.boolean().optional(), Schedule: ScheduleSchema.partial() }).partial());
|
||||||
|
|
||||||
const schemaAvailabilityCreateParams = z
|
const schemaAvailabilityCreateParams = z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod";
|
|
||||||
import { denullishShape } from "@calcom/prisma/zod-utils";
|
import { denullishShape } from "@calcom/prisma/zod-utils";
|
||||||
|
import { BookingReferenceSchema } from "@calcom/prisma/zod/modelSchema/BookingReferenceSchema";
|
||||||
|
|
||||||
export const schemaBookingReferenceBaseBodyParams = BookingReference.pick({
|
export const schemaBookingReferenceBaseBodyParams = BookingReferenceSchema.pick({
|
||||||
type: true,
|
type: true,
|
||||||
bookingId: true,
|
bookingId: true,
|
||||||
uid: true,
|
uid: true,
|
||||||
@@ -11,7 +11,7 @@ export const schemaBookingReferenceBaseBodyParams = BookingReference.pick({
|
|||||||
deleted: true,
|
deleted: true,
|
||||||
}).partial();
|
}).partial();
|
||||||
|
|
||||||
export const schemaBookingReferenceReadPublic = BookingReference.pick({
|
export const schemaBookingReferenceReadPublic = BookingReferenceSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
type: true,
|
type: true,
|
||||||
bookingId: true,
|
bookingId: true,
|
||||||
@@ -22,7 +22,7 @@ export const schemaBookingReferenceReadPublic = BookingReference.pick({
|
|||||||
deleted: true,
|
deleted: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaBookingCreateBodyParams = BookingReference.omit({ id: true, bookingId: true })
|
export const schemaBookingCreateBodyParams = BookingReferenceSchema.omit({ id: true, bookingId: true })
|
||||||
.merge(denullishShape(BookingReference.pick({ bookingId: true })))
|
.merge(denullishShape(BookingReferenceSchema.pick({ bookingId: true })))
|
||||||
.strict();
|
.strict();
|
||||||
export const schemaBookingEditBodyParams = schemaBookingCreateBodyParams.partial();
|
export const schemaBookingEditBodyParams = schemaBookingCreateBodyParams.partial();
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import { extendedBookingCreateBody } from "@calcom/features/bookings/lib/bookingCreateBodySchema";
|
||||||
_AttendeeModel,
|
|
||||||
_BookingModel as Booking,
|
|
||||||
_EventTypeModel,
|
|
||||||
_PaymentModel,
|
|
||||||
_TeamModel,
|
|
||||||
_UserModel,
|
|
||||||
} from "@calcom/prisma/zod";
|
|
||||||
import { iso8601 } from "@calcom/prisma/zod-utils";
|
import { iso8601 } from "@calcom/prisma/zod-utils";
|
||||||
import { extendedBookingCreateBody } from "@calcom/prisma/zod/custom/booking";
|
import { AttendeeSchema } from "@calcom/prisma/zod/modelSchema/AttendeeSchema";
|
||||||
|
import { BookingSchema as Booking } from "@calcom/prisma/zod/modelSchema/BookingSchema";
|
||||||
|
import { EventTypeSchema } from "@calcom/prisma/zod/modelSchema/EventTypeSchema";
|
||||||
|
import { PaymentSchema } from "@calcom/prisma/zod/modelSchema/PaymentSchema";
|
||||||
|
import { TeamSchema } from "@calcom/prisma/zod/modelSchema/TeamSchema";
|
||||||
|
import { UserSchema } from "@calcom/prisma/zod/modelSchema/UserSchema";
|
||||||
|
|
||||||
import { schemaQueryUserId } from "./shared/queryUserId";
|
import { schemaQueryUserId } from "./shared/queryUserId";
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ export const bookingCancelSchema = z.object({
|
|||||||
id: z.number(),
|
id: z.number(),
|
||||||
allRemainingBookings: z.boolean().optional(),
|
allRemainingBookings: z.boolean().optional(),
|
||||||
cancelSubsequentBookings: z.boolean().optional(),
|
cancelSubsequentBookings: z.boolean().optional(),
|
||||||
cancellationReason: z.string().min(1).optional(),
|
cancellationReason: z.string().optional().default("Not Provided"),
|
||||||
seatReferenceUid: z.string().optional(),
|
seatReferenceUid: z.string().optional(),
|
||||||
cancelledBy: z.string().email({ message: "Invalid email" }).optional(),
|
cancelledBy: z.string().email({ message: "Invalid email" }).optional(),
|
||||||
internalNote: z
|
internalNote: z
|
||||||
@@ -72,17 +70,16 @@ export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams
|
|||||||
.merge(schemaBookingEditParams)
|
.merge(schemaBookingEditParams)
|
||||||
.omit({ uid: true });
|
.omit({ uid: true });
|
||||||
|
|
||||||
const teamSchema = _TeamModel.pick({
|
const teamSchema = TeamSchema.pick({
|
||||||
name: true,
|
name: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaBookingReadPublic = Booking.extend({
|
export const schemaBookingReadPublic = Booking.extend({
|
||||||
eventType: _EventTypeModel
|
eventType: EventTypeSchema.pick({
|
||||||
.pick({
|
title: true,
|
||||||
title: true,
|
slug: true,
|
||||||
slug: true,
|
})
|
||||||
})
|
|
||||||
.merge(
|
.merge(
|
||||||
z.object({
|
z.object({
|
||||||
team: teamSchema.nullish(),
|
team: teamSchema.nullish(),
|
||||||
@@ -91,7 +88,7 @@ export const schemaBookingReadPublic = Booking.extend({
|
|||||||
.nullish(),
|
.nullish(),
|
||||||
attendees: z
|
attendees: z
|
||||||
.array(
|
.array(
|
||||||
_AttendeeModel.pick({
|
AttendeeSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
email: true,
|
email: true,
|
||||||
name: true,
|
name: true,
|
||||||
@@ -100,17 +97,15 @@ export const schemaBookingReadPublic = Booking.extend({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
user: _UserModel
|
user: UserSchema.pick({
|
||||||
.pick({
|
email: true,
|
||||||
email: true,
|
name: true,
|
||||||
name: true,
|
timeZone: true,
|
||||||
timeZone: true,
|
locale: true,
|
||||||
locale: true,
|
}).nullish(),
|
||||||
})
|
|
||||||
.nullish(),
|
|
||||||
payment: z
|
payment: z
|
||||||
.array(
|
.array(
|
||||||
_PaymentModel.pick({
|
PaymentSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
success: true,
|
success: true,
|
||||||
paymentOption: true,
|
paymentOption: true,
|
||||||
@@ -140,3 +135,8 @@ export const schemaBookingReadPublic = Booking.extend({
|
|||||||
rescheduledBy: true,
|
rescheduledBy: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
bookingCreateSchemaLegacyPropsForApi,
|
||||||
|
bookingCreateBodySchemaForApi,
|
||||||
|
} from "@calcom/features/bookings/lib/bookingCreateBodySchema";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { _DestinationCalendarModel as DestinationCalendar } from "@calcom/prisma/zod";
|
import { DestinationCalendarSchema } from "@calcom/prisma/zod/modelSchema/DestinationCalendarSchema";
|
||||||
|
|
||||||
export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.pick({
|
export const schemaDestinationCalendarBaseBodyParams = DestinationCalendarSchema.pick({
|
||||||
integration: true,
|
integration: true,
|
||||||
externalId: true,
|
externalId: true,
|
||||||
eventTypeId: true,
|
eventTypeId: true,
|
||||||
@@ -38,7 +38,7 @@ export const schemaDestinationCalendarEditBodyParams = schemaDestinationCalendar
|
|||||||
schemaDestinationCalendarEditParams
|
schemaDestinationCalendarEditParams
|
||||||
);
|
);
|
||||||
|
|
||||||
export const schemaDestinationCalendarReadPublic = DestinationCalendar.pick({
|
export const schemaDestinationCalendarReadPublic = DestinationCalendarSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
integration: true,
|
integration: true,
|
||||||
externalId: true,
|
externalId: true,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod";
|
import { EventTypeCustomInputSchema } from "@calcom/prisma/zod/modelSchema/EventTypeCustomInputSchema";
|
||||||
|
|
||||||
export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInput.omit({
|
export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInputSchema.omit({
|
||||||
id: true,
|
id: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({});
|
export const schemaEventTypeCustomInputPublic = EventTypeCustomInputSchema.omit({});
|
||||||
|
|
||||||
export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.strict();
|
export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.strict();
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import {
|
|||||||
MIN_EVENT_DURATION_MINUTES,
|
MIN_EVENT_DURATION_MINUTES,
|
||||||
} from "@calcom/lib/constants";
|
} from "@calcom/lib/constants";
|
||||||
import slugify from "@calcom/lib/slugify";
|
import slugify from "@calcom/lib/slugify";
|
||||||
import { _EventTypeModel as EventType, _HostModel } from "@calcom/prisma/zod";
|
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||||
import { customInputSchema, eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
import { EventTypeSchema } from "@calcom/prisma/zod/modelSchema/EventTypeSchema";
|
||||||
|
import { HostSchema } from "@calcom/prisma/zod/modelSchema/HostSchema";
|
||||||
|
|
||||||
import { Frequency } from "~/lib/types";
|
import { Frequency } from "~/lib/types";
|
||||||
|
|
||||||
import { jsonSchema } from "./shared/jsonSchema";
|
|
||||||
import { schemaQueryUserId } from "./shared/queryUserId";
|
import { schemaQueryUserId } from "./shared/queryUserId";
|
||||||
import { timeZone } from "./shared/timeZone";
|
import { timeZone } from "./shared/timeZone";
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ const recurringEventInputSchema = z.object({
|
|||||||
tzid: timeZone.optional(),
|
tzid: timeZone.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const hostSchema = _HostModel.pick({
|
const hostSchema = HostSchema.pick({
|
||||||
isFixed: true,
|
isFixed: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
scheduleId: true,
|
scheduleId: true,
|
||||||
@@ -35,7 +35,7 @@ export const childrenSchema = z.object({
|
|||||||
userId: z.number().int(),
|
userId: z.number().int(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaEventTypeBaseBodyParams = EventType.pick({
|
export const schemaEventTypeBaseBodyParams = EventTypeSchema.pick({
|
||||||
title: true,
|
title: true,
|
||||||
description: true,
|
description: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
@@ -117,67 +117,3 @@ const schemaEventTypeEditParams = z
|
|||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
export const schemaEventTypeEditBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeEditParams);
|
export const schemaEventTypeEditBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeEditParams);
|
||||||
export const schemaEventTypeReadPublic = EventType.pick({
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
slug: true,
|
|
||||||
length: true,
|
|
||||||
hidden: true,
|
|
||||||
position: true,
|
|
||||||
userId: true,
|
|
||||||
teamId: true,
|
|
||||||
scheduleId: true,
|
|
||||||
eventName: true,
|
|
||||||
timeZone: true,
|
|
||||||
periodType: true,
|
|
||||||
periodStartDate: true,
|
|
||||||
periodEndDate: true,
|
|
||||||
periodDays: true,
|
|
||||||
periodCountCalendarDays: true,
|
|
||||||
requiresConfirmation: true,
|
|
||||||
recurringEvent: true,
|
|
||||||
disableGuests: true,
|
|
||||||
hideCalendarNotes: true,
|
|
||||||
minimumBookingNotice: true,
|
|
||||||
beforeEventBuffer: true,
|
|
||||||
afterEventBuffer: true,
|
|
||||||
schedulingType: true,
|
|
||||||
price: true,
|
|
||||||
currency: true,
|
|
||||||
slotInterval: true,
|
|
||||||
parentId: true,
|
|
||||||
successRedirectUrl: true,
|
|
||||||
description: true,
|
|
||||||
locations: true,
|
|
||||||
metadata: true,
|
|
||||||
seatsPerTimeSlot: true,
|
|
||||||
seatsShowAttendees: true,
|
|
||||||
seatsShowAvailabilityCount: true,
|
|
||||||
bookingFields: true,
|
|
||||||
bookingLimits: true,
|
|
||||||
onlyShowFirstAvailableSlot: true,
|
|
||||||
durationLimits: true,
|
|
||||||
}).merge(
|
|
||||||
z.object({
|
|
||||||
children: z.array(childrenSchema).optional().default([]),
|
|
||||||
hosts: z.array(hostSchema).optional().default([]),
|
|
||||||
locations: z
|
|
||||||
.array(
|
|
||||||
z.object({
|
|
||||||
link: z.string().optional(),
|
|
||||||
address: z.string().optional(),
|
|
||||||
hostPhoneNumber: z.string().optional(),
|
|
||||||
type: z.any().optional(),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.nullable(),
|
|
||||||
metadata: jsonSchema.nullable(),
|
|
||||||
customInputs: customInputSchema.array().optional(),
|
|
||||||
link: z.string().optional(),
|
|
||||||
hashedLink: z
|
|
||||||
.array(z.object({ link: z.string() }))
|
|
||||||
.optional()
|
|
||||||
.default([]),
|
|
||||||
bookingFields: eventTypeBookingFields.optional().nullable(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { MembershipRole } from "@calcom/prisma/enums";
|
import { MembershipRole } from "@calcom/prisma/enums";
|
||||||
import { _MembershipModel as Membership, _TeamModel } from "@calcom/prisma/zod";
|
|
||||||
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
||||||
|
import { MembershipSchema } from "@calcom/prisma/zod/modelSchema/MembershipSchema";
|
||||||
|
import { TeamSchema } from "@calcom/prisma/zod/modelSchema/TeamSchema";
|
||||||
|
|
||||||
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
|
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
|
||||||
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
||||||
|
|
||||||
export const schemaMembershipBaseBodyParams = Membership.omit({});
|
export const schemaMembershipBaseBodyParams = MembershipSchema.omit({});
|
||||||
|
|
||||||
const schemaMembershipRequiredParams = z.object({
|
const schemaMembershipRequiredParams = z.object({
|
||||||
teamId: z.number(),
|
teamId: z.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const membershipCreateBodySchema = Membership.omit({ id: true })
|
export const membershipCreateBodySchema = MembershipSchema.omit({
|
||||||
|
id: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
})
|
||||||
.partial({
|
.partial({
|
||||||
accepted: true,
|
accepted: true,
|
||||||
role: true,
|
role: true,
|
||||||
@@ -26,11 +31,13 @@ export const membershipCreateBodySchema = Membership.omit({ id: true })
|
|||||||
...v,
|
...v,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const membershipEditBodySchema = Membership.omit({
|
export const membershipEditBodySchema = MembershipSchema.omit({
|
||||||
/** To avoid complication, let's avoid updating these, instead you can delete and create a new invite */
|
/** To avoid complication, let's avoid updating these, instead you can delete and create a new invite */
|
||||||
teamId: true,
|
teamId: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
id: true,
|
id: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
})
|
})
|
||||||
.partial({
|
.partial({
|
||||||
accepted: true,
|
accepted: true,
|
||||||
@@ -43,7 +50,7 @@ export const schemaMembershipBodyParams = schemaMembershipBaseBodyParams.merge(
|
|||||||
schemaMembershipRequiredParams
|
schemaMembershipRequiredParams
|
||||||
);
|
);
|
||||||
|
|
||||||
export const schemaMembershipPublic = Membership.merge(z.object({ team: _TeamModel }).partial());
|
export const schemaMembershipPublic = MembershipSchema.merge(z.object({ team: TeamSchema }).partial());
|
||||||
|
|
||||||
/** We extract userId and teamId from compound ID string */
|
/** We extract userId and teamId from compound ID string */
|
||||||
export const membershipIdSchema = schemaQueryIdAsString
|
export const membershipIdSchema = schemaQueryIdAsString
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { _PaymentModel as Payment } from "@calcom/prisma/zod";
|
import { PaymentSchema } from "@calcom/prisma/zod/modelSchema/PaymentSchema";
|
||||||
|
|
||||||
export const schemaPaymentPublic = Payment.pick({
|
export const schemaPaymentPublic = PaymentSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
amount: true,
|
amount: true,
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { _ReminderMailModel as ReminderMail } from "@calcom/prisma/zod";
|
import { ReminderMailSchema } from "@calcom/prisma/zod/modelSchema/ReminderMailSchema";
|
||||||
|
|
||||||
export const schemaReminderMailBaseBodyParams = ReminderMail.omit({ id: true }).partial();
|
export const schemaReminderMailBaseBodyParams = ReminderMailSchema.omit({ id: true }).partial();
|
||||||
|
|
||||||
export const schemaReminderMailPublic = ReminderMail.omit({});
|
export const schemaReminderMailPublic = ReminderMailSchema.omit({});
|
||||||
|
|
||||||
const schemaReminderMailRequiredParams = z.object({
|
const schemaReminderMailRequiredParams = z.object({
|
||||||
referenceId: z.number().int(),
|
referenceId: z.number().int(),
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { _ScheduleModel as Schedule, _AvailabilityModel as Availability } from "@calcom/prisma/zod";
|
import { AvailabilitySchema } from "@calcom/prisma/zod/modelSchema/AvailabilitySchema";
|
||||||
|
import { ScheduleSchema } from "@calcom/prisma/zod/modelSchema/ScheduleSchema";
|
||||||
|
|
||||||
import { timeZone } from "./shared/timeZone";
|
import { timeZone } from "./shared/timeZone";
|
||||||
|
|
||||||
const schemaScheduleBaseBodyParams = Schedule.omit({ id: true, timeZone: true }).partial();
|
const schemaScheduleBaseBodyParams = ScheduleSchema.omit({ id: true, timeZone: true }).partial();
|
||||||
|
|
||||||
export const schemaSingleScheduleBodyParams = schemaScheduleBaseBodyParams.merge(
|
export const schemaSingleScheduleBodyParams = schemaScheduleBaseBodyParams.merge(
|
||||||
z.object({ userId: z.number().optional(), timeZone: timeZone.optional() })
|
z.object({ userId: z.number().optional(), timeZone: timeZone.optional() })
|
||||||
@@ -17,12 +18,12 @@ export const schemaCreateScheduleBodyParams = schemaScheduleBaseBodyParams.merge
|
|||||||
|
|
||||||
export const schemaSchedulePublic = z
|
export const schemaSchedulePublic = z
|
||||||
.object({ id: z.number() })
|
.object({ id: z.number() })
|
||||||
.merge(Schedule)
|
.merge(ScheduleSchema)
|
||||||
.merge(
|
.merge(
|
||||||
z.object({
|
z.object({
|
||||||
availability: z
|
availability: z
|
||||||
.array(
|
.array(
|
||||||
Availability.pick({
|
AvailabilitySchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
eventTypeId: true,
|
eventTypeId: true,
|
||||||
date: true,
|
date: true,
|
||||||
|
|||||||
@@ -1,28 +1,22 @@
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod";
|
import { SelectedCalendarSchema } from "@calcom/prisma/zod/modelSchema/SelectedCalendarSchema";
|
||||||
|
|
||||||
import { schemaQueryIdAsString } from "./shared/queryIdString";
|
import { schemaQueryIdAsString } from "./shared/queryIdString";
|
||||||
import { schemaQueryIdParseInt } from "./shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "./shared/queryIdTransformParseInt";
|
||||||
|
|
||||||
export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar;
|
export const schemaSelectedCalendarBaseBodyParams = SelectedCalendarSchema;
|
||||||
|
|
||||||
export const schemaSelectedCalendarPublic = SelectedCalendar.omit({});
|
export const schemaSelectedCalendarPublic = SelectedCalendarSchema.omit({});
|
||||||
|
|
||||||
export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams
|
export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams
|
||||||
.partial({
|
.pick({
|
||||||
|
integration: true,
|
||||||
|
externalId: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
})
|
})
|
||||||
.omit({
|
.partial({
|
||||||
// id will be set by the database
|
userId: true,
|
||||||
id: true,
|
|
||||||
// No eventTypeId support in API v1
|
|
||||||
eventTypeId: true,
|
|
||||||
|
|
||||||
/** No watch related fields support in API v1 */
|
|
||||||
watchAttempts: true,
|
|
||||||
unwatchAttempts: true,
|
|
||||||
maxAttempts: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaSelectedCalendarUpdateBodyParams = schemaSelectedCalendarBaseBodyParams
|
export const schemaSelectedCalendarUpdateBodyParams = schemaSelectedCalendarBaseBodyParams
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { _TeamModel as Team } from "@calcom/prisma/zod";
|
import { TeamSchema } from "@calcom/prisma/zod/modelSchema/TeamSchema";
|
||||||
|
|
||||||
export const schemaTeamBaseBodyParams = Team.omit({ id: true, createdAt: true }).partial({
|
export const schemaTeamBaseBodyParams = TeamSchema.omit({ id: true, createdAt: true }).partial({
|
||||||
hideBranding: true,
|
hideBranding: true,
|
||||||
metadata: true,
|
metadata: true,
|
||||||
pendingPayment: true,
|
pendingPayment: true,
|
||||||
@@ -28,6 +28,6 @@ const schemaOwnerId = z.object({
|
|||||||
|
|
||||||
export const schemaTeamCreateBodyParams = schemaTeamBodyParams.merge(schemaOwnerId).strict();
|
export const schemaTeamCreateBodyParams = schemaTeamBodyParams.merge(schemaOwnerId).strict();
|
||||||
|
|
||||||
export const schemaTeamReadPublic = Team.omit({});
|
export const schemaTeamReadPublic = TeamSchema.omit({});
|
||||||
|
|
||||||
export const schemaTeamsReadPublic = z.array(schemaTeamReadPublic);
|
export const schemaTeamsReadPublic = z.array(schemaTeamReadPublic);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||||
import { checkUsername } from "@calcom/lib/server/checkUsername";
|
import { checkUsername } from "@calcom/lib/server/checkUsername";
|
||||||
import { _UserModel as User } from "@calcom/prisma/zod";
|
|
||||||
import { iso8601 } from "@calcom/prisma/zod-utils";
|
import { iso8601 } from "@calcom/prisma/zod-utils";
|
||||||
|
import { UserSchema } from "@calcom/prisma/zod/modelSchema/UserSchema";
|
||||||
|
|
||||||
import { isValidBase64Image } from "~/lib/utils/isValidBase64Image";
|
import { isValidBase64Image } from "~/lib/utils/isValidBase64Image";
|
||||||
import { timeZone } from "~/lib/validations/shared/timeZone";
|
import { timeZone } from "~/lib/validations/shared/timeZone";
|
||||||
@@ -68,7 +68,7 @@ const usernameSchema = z
|
|||||||
});
|
});
|
||||||
|
|
||||||
// @note: These are the values that are editable via PATCH method on the user Model
|
// @note: These are the values that are editable via PATCH method on the user Model
|
||||||
export const schemaUserBaseBodyParams = User.pick({
|
export const schemaUserBaseBodyParams = UserSchema.pick({
|
||||||
name: true,
|
name: true,
|
||||||
email: true,
|
email: true,
|
||||||
username: true,
|
username: true,
|
||||||
@@ -151,7 +151,7 @@ export const schemaUserCreateBodyParams = schemaUserBaseBodyParams
|
|||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
// @note: These are the values that are always returned when reading a user
|
// @note: These are the values that are always returned when reading a user
|
||||||
export const schemaUserReadPublic = User.pick({
|
export const schemaUserReadPublic = UserSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
username: true,
|
username: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { WEBHOOK_TRIGGER_EVENTS } from "@calcom/features/webhooks/lib/constants";
|
import { WEBHOOK_TRIGGER_EVENTS } from "@calcom/features/webhooks/lib/constants";
|
||||||
import { _WebhookModel as Webhook } from "@calcom/prisma/zod";
|
import { WebhookSchema } from "@calcom/prisma/zod/modelSchema/WebhookSchema";
|
||||||
|
|
||||||
const schemaWebhookBaseBodyParams = Webhook.pick({
|
const schemaWebhookBaseBodyParams = WebhookSchema.pick({
|
||||||
userId: true,
|
userId: true,
|
||||||
eventTypeId: true,
|
eventTypeId: true,
|
||||||
eventTriggers: true,
|
eventTriggers: true,
|
||||||
@@ -38,7 +38,7 @@ export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams
|
|||||||
.partial()
|
.partial()
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
export const schemaWebhookReadPublic = Webhook.pick({
|
export const schemaWebhookReadPublic = WebhookSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
userId: true,
|
userId: true,
|
||||||
eventTypeId: true,
|
eventTypeId: true,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const { withAxiom } = require("next-axiom");
|
const { withAxiom } = require("next-axiom");
|
||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
const { PrismaPlugin } = require("@prisma/nextjs-monorepo-workaround-plugin");
|
||||||
|
|
||||||
const plugins = [withAxiom];
|
const plugins = [withAxiom];
|
||||||
|
|
||||||
@@ -14,6 +15,12 @@ const nextConfig = {
|
|||||||
"@calcom/prisma",
|
"@calcom/prisma",
|
||||||
"@calcom/trpc",
|
"@calcom/trpc",
|
||||||
],
|
],
|
||||||
|
webpack: (config, { isServer }) => {
|
||||||
|
if (isServer) {
|
||||||
|
config.plugins = [...config.plugins, new PrismaPlugin()];
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
async headers() {
|
async headers() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"@calcom/lib": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
"@calcom/trpc": "*",
|
"@calcom/trpc": "*",
|
||||||
|
"@prisma/nextjs-monorepo-workaround-plugin": "^6.16.1",
|
||||||
"@sentry/nextjs": "^9.15.0",
|
"@sentry/nextjs": "^9.15.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
import type { Ensure } from "@calcom/types/utils";
|
import type { Ensure } from "@calcom/types/utils";
|
||||||
|
|
||||||
import { apiKeyPublicSchema } from "~/lib/validations/api-key";
|
import { apiKeyPublicSchema } from "~/lib/validations/api-key";
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
|
|
||||||
@@ -6,6 +5,7 @@ import { generateUniqueAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys";
|
|||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key";
|
import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key";
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaAttendeeReadPublic } from "~/lib/validations/attendee";
|
import { schemaAttendeeReadPublic } from "~/lib/validations/attendee";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
schemaBookingEditBodyParams,
|
schemaBookingEditBodyParams,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-reference";
|
import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-reference";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
schemaBookingCreateBodyParams,
|
schemaBookingCreateBodyParams,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import prisma from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
|
|
||||||
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||||
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
||||||
@@ -34,7 +34,14 @@ async function authMiddleware(req: NextApiRequest) {
|
|||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
select: {
|
select: {
|
||||||
email: true,
|
email: true,
|
||||||
bookings: true,
|
bookings: {
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -102,8 +102,11 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
const booking = await prisma.booking.findUnique({
|
const booking = await prisma.booking.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
include: {
|
include: {
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
attendees: true,
|
attendees: true,
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
user: true,
|
user: true,
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
payment: true,
|
payment: true,
|
||||||
eventType: expand.includes("team") ? { include: { team: true } } : false,
|
eventType: expand.includes("team") ? { include: { team: true } } : false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
|
||||||
import {
|
import {
|
||||||
getRecordingsOfCalVideoByRoomName,
|
getRecordingsOfCalVideoByRoomName,
|
||||||
getDownloadLinkOfCalVideoByRecordingId,
|
getDownloadLinkOfCalVideoByRecordingId,
|
||||||
} from "@calcom/lib/videoClient";
|
} from "@calcom/app-store/videoClient";
|
||||||
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import type { RecordingItemSchema } from "@calcom/prisma/zod-utils";
|
import type { RecordingItemSchema } from "@calcom/prisma/zod-utils";
|
||||||
import type { PartialReference } from "@calcom/types/EventManager";
|
import type { PartialReference } from "@calcom/types/EventManager";
|
||||||
@@ -63,6 +63,7 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
|
|
||||||
const booking = await prisma.booking.findUnique({
|
const booking = await prisma.booking.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
include: { references: true },
|
include: { references: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
|
||||||
import {
|
import {
|
||||||
getTranscriptsAccessLinkFromRecordingId,
|
getTranscriptsAccessLinkFromRecordingId,
|
||||||
checkIfRoomNameMatchesInRecording,
|
checkIfRoomNameMatchesInRecording,
|
||||||
} from "@calcom/lib/videoClient";
|
} from "@calcom/app-store/videoClient";
|
||||||
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import type { PartialReference } from "@calcom/types/EventManager";
|
import type { PartialReference } from "@calcom/types/EventManager";
|
||||||
|
|
||||||
@@ -61,6 +61,7 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
const checkIfRecordingBelongsToBooking = async (bookingId: number, recordingId: string) => {
|
const checkIfRecordingBelongsToBooking = async (bookingId: number, recordingId: string) => {
|
||||||
const booking = await prisma.booking.findUnique({
|
const booking = await prisma.booking.findUnique({
|
||||||
where: { id: bookingId },
|
where: { id: bookingId },
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
include: { references: true },
|
include: { references: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
|
import { getAllTranscriptsAccessLinkFromRoomName } from "@calcom/app-store/videoClient";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import { getAllTranscriptsAccessLinkFromRoomName } from "@calcom/lib/videoClient";
|
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import type { PartialReference } from "@calcom/types/EventManager";
|
import type { PartialReference } from "@calcom/types/EventManager";
|
||||||
|
|
||||||
@@ -44,6 +44,7 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
|
|
||||||
const booking = await prisma.booking.findUnique({
|
const booking = await prisma.booking.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
include: { references: true },
|
include: { references: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma, Booking } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma, Booking } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { withMiddleware } from "~/lib/helpers/withMiddleware";
|
import { withMiddleware } from "~/lib/helpers/withMiddleware";
|
||||||
import { buildWhereClause } from "~/lib/utils/bookings/get/buildWhereClause";
|
import { buildWhereClause } from "~/lib/utils/bookings/get/buildWhereClause";
|
||||||
|
|||||||
@@ -80,7 +80,13 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
const { query } = req;
|
const { query } = req;
|
||||||
const { id } = schemaQueryIdParseInt.parse(query);
|
const { id } = schemaQueryIdParseInt.parse(query);
|
||||||
const data = schemaEventTypeCustomInputEditBodyParams.parse(req.body);
|
const data = schemaEventTypeCustomInputEditBodyParams.parse(req.body);
|
||||||
const result = await prisma.eventTypeCustomInput.update({ where: { id }, data });
|
const result = await prisma.eventTypeCustomInput.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
options: data.options === null ? [] : data.options,
|
||||||
|
},
|
||||||
|
});
|
||||||
return { event_type_custom_input: schemaEventTypeCustomInputPublic.parse(result) };
|
return { event_type_custom_input: schemaEventTypeCustomInputPublic.parse(result) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-custom-input";
|
import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-custom-input";
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,11 @@ async function postHandler(req: NextApiRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await prisma.eventTypeCustomInput.create({
|
const data = await prisma.eventTypeCustomInput.create({
|
||||||
data: { ...body, eventType: { connect: { id: eventTypeId } } },
|
data: {
|
||||||
|
...body,
|
||||||
|
options: body.options === null ? [] : body.options,
|
||||||
|
eventType: { connect: { id: eventTypeId } },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
|
||||||
import { getCalendarCredentialsWithoutDelegation, getConnectedCalendars } from "@calcom/lib/CalendarManager";
|
import {
|
||||||
|
getCalendarCredentialsWithoutDelegation,
|
||||||
|
getConnectedCalendars,
|
||||||
|
} from "@calcom/features/calendars/lib/CalendarManager";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import type { PrismaClient } from "@calcom/prisma";
|
import type { PrismaClient } from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { getCalendarCredentialsWithoutDelegation, getConnectedCalendars } from "@calcom/lib/CalendarManager";
|
import {
|
||||||
|
getCalendarCredentialsWithoutDelegation,
|
||||||
|
getConnectedCalendars,
|
||||||
|
} from "@calcom/features/calendars/lib/CalendarManager";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { prisma } from "@calcom/prisma";
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
|
|
||||||
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
||||||
|
|
||||||
@@ -66,4 +65,4 @@ async function checkPermissions(req: NextApiRequest) {
|
|||||||
throw new HttpError({ statusCode: 403, message: "Forbidden" });
|
throw new HttpError({ statusCode: 403, message: "Forbidden" });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defaultResponder(deleteHandler);
|
export default deleteHandler;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { prisma } from "@calcom/prisma";
|
||||||
import prisma from "@calcom/prisma";
|
|
||||||
import { MembershipRole } from "@calcom/prisma/enums";
|
import { MembershipRole } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
|
import { eventTypeSelect } from "~/lib/selects/event-type";
|
||||||
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
||||||
import { checkPermissions as canAccessTeamEventOrThrow } from "~/pages/api/teams/[teamId]/_auth-middleware";
|
import { checkPermissions as canAccessTeamEventOrThrow } from "~/pages/api/teams/[teamId]/_auth-middleware";
|
||||||
|
|
||||||
@@ -49,15 +48,13 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
|
|
||||||
const eventType = await prisma.eventType.findUnique({
|
const eventType = await prisma.eventType.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
include: {
|
select: eventTypeSelect,
|
||||||
customInputs: true,
|
|
||||||
hashedLink: { select: { link: true } },
|
|
||||||
team: { select: { slug: true } },
|
|
||||||
hosts: { select: { userId: true, isFixed: true } },
|
|
||||||
owner: { select: { username: true, id: true } },
|
|
||||||
children: { select: { id: true, userId: true } },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!eventType) {
|
||||||
|
throw new HttpError({ statusCode: 404, message: "Event type not found" });
|
||||||
|
}
|
||||||
|
|
||||||
await checkPermissions(req, eventType);
|
await checkPermissions(req, eventType);
|
||||||
|
|
||||||
const link = eventType ? getCalLink(eventType) : null;
|
const link = eventType ? getCalLink(eventType) : null;
|
||||||
@@ -74,9 +71,12 @@ export async function getHandler(req: NextApiRequest) {
|
|||||||
eventType.scheduleId = user.defaultScheduleId;
|
eventType.scheduleId = user.defaultScheduleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: eventType when not found should be a 404
|
return {
|
||||||
// but API consumers may depend on the {} behaviour.
|
event_type: {
|
||||||
return { event_type: schemaEventTypeReadPublic.parse({ ...eventType, link }) };
|
...eventType,
|
||||||
|
link,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseEventTypeCheckPermissions = {
|
type BaseEventTypeCheckPermissions = {
|
||||||
@@ -100,4 +100,4 @@ async function checkPermissions<T extends BaseEventTypeCheckPermissions>(
|
|||||||
throw new HttpError({ statusCode: 403, message: "Forbidden" });
|
throw new HttpError({ statusCode: 403, message: "Forbidden" });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defaultResponder(getHandler);
|
export default getHandler;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { prisma } from "@calcom/prisma";
|
||||||
import prisma from "@calcom/prisma";
|
import { Prisma } from "@calcom/prisma/client";
|
||||||
import { SchedulingType } from "@calcom/prisma/enums";
|
import { SchedulingType } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
|
import { eventTypeSelect } from "~/lib/selects/event-type";
|
||||||
import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type";
|
import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type";
|
||||||
import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type";
|
import { schemaEventTypeEditBodyParams } from "~/lib/validations/event-type";
|
||||||
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
|
||||||
import ensureOnlyMembersAsHosts from "~/pages/api/event-types/_utils/ensureOnlyMembersAsHosts";
|
import ensureOnlyMembersAsHosts from "~/pages/api/event-types/_utils/ensureOnlyMembersAsHosts";
|
||||||
|
|
||||||
@@ -210,6 +210,7 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
hosts = [],
|
hosts = [],
|
||||||
bookingLimits,
|
bookingLimits,
|
||||||
durationLimits,
|
durationLimits,
|
||||||
|
locations,
|
||||||
/** FIXME: Updating event-type children from API not supported for now */
|
/** FIXME: Updating event-type children from API not supported for now */
|
||||||
children: _,
|
children: _,
|
||||||
...parsedBody
|
...parsedBody
|
||||||
@@ -217,8 +218,10 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
|
|
||||||
const data: Prisma.EventTypeUpdateArgs["data"] = {
|
const data: Prisma.EventTypeUpdateArgs["data"] = {
|
||||||
...parsedBody,
|
...parsedBody,
|
||||||
|
teamId: parsedBody.teamId === null ? undefined : parsedBody.teamId,
|
||||||
bookingLimits: bookingLimits === null ? Prisma.DbNull : bookingLimits,
|
bookingLimits: bookingLimits === null ? Prisma.DbNull : bookingLimits,
|
||||||
durationLimits: durationLimits === null ? Prisma.DbNull : durationLimits,
|
durationLimits: durationLimits === null ? Prisma.DbNull : durationLimits,
|
||||||
|
locations: locations === null ? Prisma.DbNull : locations,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (hosts) {
|
if (hosts) {
|
||||||
@@ -232,8 +235,8 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
await checkPermissions(req, parsedBody);
|
await checkPermissions(req, parsedBody);
|
||||||
const eventType = await prisma.eventType.update({ where: { id }, data });
|
const eventType = await prisma.eventType.update({ where: { id }, data, select: eventTypeSelect });
|
||||||
return { event_type: schemaEventTypeReadPublic.parse(eventType) };
|
return { event_type: eventType };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkPermissions(req: NextApiRequest, body: z.infer<typeof schemaEventTypeBaseBodyParams>) {
|
async function checkPermissions(req: NextApiRequest, body: z.infer<typeof schemaEventTypeBaseBodyParams>) {
|
||||||
@@ -246,4 +249,4 @@ async function checkPermissions(req: NextApiRequest, body: z.infer<typeof schema
|
|||||||
await checkTeamEventEditPermission(req, body);
|
await checkTeamEventEditPermission(req, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defaultResponder(patchHandler);
|
export default patchHandler;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import type { NextApiRequest } from "next";
|
|||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
import type { PrismaClient } from "@calcom/prisma";
|
import type { PrismaClient } from "@calcom/prisma";
|
||||||
|
|
||||||
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
|
import { eventTypeSelect } from "~/lib/selects/event-type";
|
||||||
import { schemaQuerySlug } from "~/lib/validations/shared/querySlug";
|
import { schemaQuerySlug } from "~/lib/validations/shared/querySlug";
|
||||||
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
||||||
|
|
||||||
@@ -54,14 +54,7 @@ async function getHandler(req: NextApiRequest) {
|
|||||||
userId: shouldUseUserId ? { in: userIds } : undefined,
|
userId: shouldUseUserId ? { in: userIds } : undefined,
|
||||||
slug: slug, // slug will be undefined if not provided in query
|
slug: slug, // slug will be undefined if not provided in query
|
||||||
},
|
},
|
||||||
include: {
|
select: eventTypeSelect,
|
||||||
customInputs: true,
|
|
||||||
hashedLink: { select: { link: true } },
|
|
||||||
team: { select: { slug: true } },
|
|
||||||
hosts: { select: { userId: true, isFixed: true } },
|
|
||||||
owner: { select: { username: true, id: true } },
|
|
||||||
children: { select: { id: true, userId: true } },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// this really should return [], but backwards compatibility..
|
// this really should return [], but backwards compatibility..
|
||||||
if (data.length === 0) new HttpError({ statusCode: 404, message: "No event types were found" });
|
if (data.length === 0) new HttpError({ statusCode: 404, message: "No event types were found" });
|
||||||
@@ -69,7 +62,7 @@ async function getHandler(req: NextApiRequest) {
|
|||||||
event_types: (await defaultScheduleId<(typeof data)[number]>({ eventTypes: data, prisma, userIds })).map(
|
event_types: (await defaultScheduleId<(typeof data)[number]>({ eventTypes: data, prisma, userIds })).map(
|
||||||
(eventType) => {
|
(eventType) => {
|
||||||
const link = getCalLink(eventType);
|
const link = getCalLink(eventType);
|
||||||
return schemaEventTypeReadPublic.parse({ ...eventType, link });
|
return { ...eventType, link };
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
|
import { Prisma } from "@calcom/prisma/client";
|
||||||
import { MembershipRole } from "@calcom/prisma/enums";
|
import { MembershipRole } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type";
|
import { eventTypeSelect } from "~/lib/selects/event-type";
|
||||||
|
import { schemaEventTypeCreateBodyParams } from "~/lib/validations/event-type";
|
||||||
import { canUserAccessTeamWithRole } from "~/pages/api/teams/[teamId]/_auth-middleware";
|
import { canUserAccessTeamWithRole } from "~/pages/api/teams/[teamId]/_auth-middleware";
|
||||||
|
|
||||||
import checkParentEventOwnership from "./_utils/checkParentEventOwnership";
|
import checkParentEventOwnership from "./_utils/checkParentEventOwnership";
|
||||||
@@ -265,14 +266,17 @@ import ensureOnlyMembersAsHosts from "./_utils/ensureOnlyMembersAsHosts";
|
|||||||
* description: Authorization information is missing or invalid.
|
* description: Authorization information is missing or invalid.
|
||||||
*/
|
*/
|
||||||
async function postHandler(req: NextApiRequest) {
|
async function postHandler(req: NextApiRequest) {
|
||||||
const { userId, isSystemWideAdmin, body } = req;
|
const { userId: ctxUserId, isSystemWideAdmin, body } = req;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hosts = [],
|
hosts = [],
|
||||||
bookingLimits,
|
bookingLimits,
|
||||||
durationLimits,
|
durationLimits,
|
||||||
|
locations,
|
||||||
/** FIXME: Adding event-type children from API not supported for now */
|
/** FIXME: Adding event-type children from API not supported for now */
|
||||||
children: _,
|
children: _,
|
||||||
|
// if userId is not passed, we will use the userId from the context
|
||||||
|
userId = ctxUserId,
|
||||||
...parsedBody
|
...parsedBody
|
||||||
} = schemaEventTypeCreateBodyParams.parse(body || {});
|
} = schemaEventTypeCreateBodyParams.parse(body || {});
|
||||||
|
|
||||||
@@ -282,6 +286,7 @@ async function postHandler(req: NextApiRequest) {
|
|||||||
users: !!parsedBody.teamId ? undefined : { connect: { id: userId } },
|
users: !!parsedBody.teamId ? undefined : { connect: { id: userId } },
|
||||||
bookingLimits: bookingLimits === null ? Prisma.DbNull : bookingLimits,
|
bookingLimits: bookingLimits === null ? Prisma.DbNull : bookingLimits,
|
||||||
durationLimits: durationLimits === null ? Prisma.DbNull : durationLimits,
|
durationLimits: durationLimits === null ? Prisma.DbNull : durationLimits,
|
||||||
|
locations: locations === null ? Prisma.DbNull : locations,
|
||||||
};
|
};
|
||||||
|
|
||||||
await checkPermissions(req);
|
await checkPermissions(req);
|
||||||
@@ -291,8 +296,8 @@ async function postHandler(req: NextApiRequest) {
|
|||||||
await checkUserMembership(req);
|
await checkUserMembership(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSystemWideAdmin && parsedBody.userId && !parsedBody.teamId) {
|
if (isSystemWideAdmin && userId && parsedBody.teamId === undefined) {
|
||||||
data = { ...parsedBody, users: { connect: { id: parsedBody.userId } } };
|
data = { ...parsedBody, users: { connect: { id: userId } } };
|
||||||
}
|
}
|
||||||
|
|
||||||
await checkTeamEventEditPermission(req, parsedBody);
|
await checkTeamEventEditPermission(req, parsedBody);
|
||||||
@@ -302,10 +307,10 @@ async function postHandler(req: NextApiRequest) {
|
|||||||
data.hosts = { createMany: { data: hosts } };
|
data.hosts = { createMany: { data: hosts } };
|
||||||
}
|
}
|
||||||
|
|
||||||
const eventType = await prisma.eventType.create({ data, include: { hosts: true } });
|
const eventType = await prisma.eventType.create({ data, select: eventTypeSelect });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
event_type: schemaEventTypeReadPublic.parse(eventType),
|
event_type: eventType,
|
||||||
message: "Event type created successfully",
|
message: "Event type created successfully",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { membershipIdSchema, schemaMembershipPublic } from "~/lib/validations/membership";
|
import { membershipIdSchema, schemaMembershipPublic } from "~/lib/validations/membership";
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
membershipEditBodySchema,
|
membershipEditBodySchema,
|
||||||
@@ -43,7 +43,13 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
const { query } = req;
|
const { query } = req;
|
||||||
const userId_teamId = membershipIdSchema.parse(query);
|
const userId_teamId = membershipIdSchema.parse(query);
|
||||||
const data = membershipEditBodySchema.parse(req.body);
|
const data = membershipEditBodySchema.parse(req.body);
|
||||||
const args: Prisma.MembershipUpdateArgs = { where: { userId_teamId }, data };
|
const args: Prisma.MembershipUpdateArgs = {
|
||||||
|
where: { userId_teamId },
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
await checkPermissions(req);
|
await checkPermissions(req);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaMembershipPublic } from "~/lib/validations/membership";
|
import { schemaMembershipPublic } from "~/lib/validations/membership";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { membershipCreateBodySchema, schemaMembershipPublic } from "~/lib/validations/membership";
|
import { membershipCreateBodySchema, schemaMembershipPublic } from "~/lib/validations/membership";
|
||||||
|
|
||||||
@@ -25,10 +25,7 @@ import { membershipCreateBodySchema, schemaMembershipPublic } from "~/lib/valida
|
|||||||
async function postHandler(req: NextApiRequest) {
|
async function postHandler(req: NextApiRequest) {
|
||||||
const data = membershipCreateBodySchema.parse(req.body);
|
const data = membershipCreateBodySchema.parse(req.body);
|
||||||
const args: Prisma.MembershipCreateArgs = {
|
const args: Prisma.MembershipCreateArgs = {
|
||||||
data: {
|
data,
|
||||||
createdAt: new Date(),
|
|
||||||
...data,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
await checkPermissions(req);
|
await checkPermissions(req);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export async function paymentById(
|
|||||||
if (safeQuery.success && method === "GET") {
|
if (safeQuery.success && method === "GET") {
|
||||||
const userWithBookings = await prisma.user.findUnique({
|
const userWithBookings = await prisma.user.findUnique({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
include: { bookings: true },
|
include: { bookings: true },
|
||||||
});
|
});
|
||||||
await prisma.payment
|
await prisma.payment
|
||||||
|
|||||||
@@ -75,7 +75,11 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
|
|||||||
export async function getHandler(req: NextApiRequest) {
|
export async function getHandler(req: NextApiRequest) {
|
||||||
const { query } = req;
|
const { query } = req;
|
||||||
const { id } = schemaQueryIdParseInt.parse(query);
|
const { id } = schemaQueryIdParseInt.parse(query);
|
||||||
const data = await prisma.schedule.findUniqueOrThrow({ where: { id }, include: { availability: true } });
|
const data = await prisma.schedule.findUniqueOrThrow({
|
||||||
|
where: { id },
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
|
include: { availability: true },
|
||||||
|
});
|
||||||
return { schedule: schemaSchedulePublic.parse(data) };
|
return { schedule: schemaSchedulePublic.parse(data) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaSchedulePublic } from "~/lib/validations/schedule";
|
import { schemaSchedulePublic } from "~/lib/validations/schedule";
|
||||||
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/validations/schedule";
|
import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/validations/schedule";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
@@ -6,6 +5,7 @@ import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
|||||||
import type { UpdateArguments } from "@calcom/lib/server/repository/selectedCalendar";
|
import type { UpdateArguments } from "@calcom/lib/server/repository/selectedCalendar";
|
||||||
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
schemaSelectedCalendarPublic,
|
schemaSelectedCalendarPublic,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
schemaSelectedCalendarBodyParams,
|
schemaSelectedCalendarBodyParams,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
import { MembershipRole } from "@calcom/prisma/enums";
|
import { MembershipRole } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
|
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
|
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
|
||||||
import { schemaTeamReadPublic } from "~/lib/validations/team";
|
import { schemaTeamReadPublic } from "~/lib/validations/team";
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments";
|
import { purchaseTeamOrOrgSubscription } from "@calcom/features/ee/teams/lib/payments";
|
||||||
@@ -6,6 +5,7 @@ import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
|
|||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ export async function patchHandler(req: NextApiRequest) {
|
|||||||
|
|
||||||
/** Only OWNERS and ADMINS can edit teams */
|
/** Only OWNERS and ADMINS can edit teams */
|
||||||
const _team = await prisma.team.findFirst({
|
const _team = await prisma.team.findFirst({
|
||||||
|
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
|
||||||
include: { members: true },
|
include: { members: true },
|
||||||
where: { id: teamId, members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } },
|
where: { id: teamId, members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
|
import { eventTypeSelect } from "~/lib/selects/event-type";
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
teamId: z.coerce.number(),
|
teamId: z.coerce.number(),
|
||||||
@@ -57,17 +57,11 @@ async function getHandler(req: NextApiRequest) {
|
|||||||
members: { some: { userId } },
|
members: { some: { userId } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
select: eventTypeSelect,
|
||||||
customInputs: true,
|
};
|
||||||
team: { select: { slug: true } },
|
return {
|
||||||
hosts: { select: { userId: true, isFixed: true } },
|
event_types: await prisma.eventType.findMany(args),
|
||||||
owner: { select: { username: true, id: true } },
|
|
||||||
children: { select: { id: true, userId: true } },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = await prisma.eventType.findMany(args);
|
|
||||||
return { event_types: data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defaultResponder(getHandler);
|
export default defaultResponder(getHandler);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaTeamsReadPublic } from "~/lib/validations/team";
|
import { schemaTeamsReadPublic } from "~/lib/validations/team";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { withMiddleware } from "~/lib/helpers/withMiddleware";
|
import { withMiddleware } from "~/lib/helpers/withMiddleware";
|
||||||
import { schemaQuerySingleOrMultipleUserEmails } from "~/lib/validations/shared/queryUserEmail";
|
import { schemaQuerySingleOrMultipleUserEmails } from "~/lib/validations/shared/queryUserEmail";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
|
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
|
||||||
import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
|
||||||
import { schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
import { schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook";
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { buildBooking } from "@calcom/lib/test/builder";
|
|||||||
import {
|
import {
|
||||||
getRecordingsOfCalVideoByRoomName,
|
getRecordingsOfCalVideoByRoomName,
|
||||||
getDownloadLinkOfCalVideoByRecordingId,
|
getDownloadLinkOfCalVideoByRecordingId,
|
||||||
} from "@calcom/lib/videoClient";
|
} from "@calcom/app-store/videoClient";
|
||||||
|
|
||||||
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ type CustomNextApiResponse = NextApiResponse & Response;
|
|||||||
const adminUserId = 1;
|
const adminUserId = 1;
|
||||||
const memberUserId = 10;
|
const memberUserId = 10;
|
||||||
|
|
||||||
vi.mock("@calcom/lib/videoClient", () => {
|
vi.mock("@calcom/app-store/videoClient", () => {
|
||||||
return {
|
return {
|
||||||
getRecordingsOfCalVideoByRoomName: vi.fn(),
|
getRecordingsOfCalVideoByRoomName: vi.fn(),
|
||||||
getDownloadLinkOfCalVideoByRecordingId: vi.fn(),
|
getDownloadLinkOfCalVideoByRecordingId: vi.fn(),
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
|||||||
import { createMocks } from "node-mocks-http";
|
import { createMocks } from "node-mocks-http";
|
||||||
import { describe, expect, test, vi, afterEach } from "vitest";
|
import { describe, expect, test, vi, afterEach } from "vitest";
|
||||||
|
|
||||||
import { buildBooking } from "@calcom/lib/test/builder";
|
|
||||||
import {
|
import {
|
||||||
getTranscriptsAccessLinkFromRecordingId,
|
getTranscriptsAccessLinkFromRecordingId,
|
||||||
checkIfRoomNameMatchesInRecording,
|
checkIfRoomNameMatchesInRecording,
|
||||||
} from "@calcom/lib/videoClient";
|
} from "@calcom/app-store/videoClient";
|
||||||
|
import { buildBooking } from "@calcom/lib/test/builder";
|
||||||
|
|
||||||
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ import handler from "../../../../../../pages/api/bookings/[id]/transcripts/[reco
|
|||||||
type CustomNextApiRequest = NextApiRequest & Request;
|
type CustomNextApiRequest = NextApiRequest & Request;
|
||||||
type CustomNextApiResponse = NextApiResponse & Response;
|
type CustomNextApiResponse = NextApiResponse & Response;
|
||||||
|
|
||||||
vi.mock("@calcom/lib/videoClient", () => {
|
vi.mock("@calcom/app-store/videoClient", () => {
|
||||||
return {
|
return {
|
||||||
getTranscriptsAccessLinkFromRecordingId: vi.fn(),
|
getTranscriptsAccessLinkFromRecordingId: vi.fn(),
|
||||||
checkIfRoomNameMatchesInRecording: vi.fn(),
|
checkIfRoomNameMatchesInRecording: vi.fn(),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createMocks } from "node-mocks-http";
|
|||||||
import { describe, expect, test, vi, afterEach } from "vitest";
|
import { describe, expect, test, vi, afterEach } from "vitest";
|
||||||
|
|
||||||
import { buildBooking } from "@calcom/lib/test/builder";
|
import { buildBooking } from "@calcom/lib/test/builder";
|
||||||
import { getAllTranscriptsAccessLinkFromRoomName } from "@calcom/lib/videoClient";
|
import { getAllTranscriptsAccessLinkFromRoomName } from "@calcom/app-store/videoClient";
|
||||||
|
|
||||||
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ import handler from "../../../../../pages/api/bookings/[id]/transcripts/_get";
|
|||||||
type CustomNextApiRequest = NextApiRequest & Request;
|
type CustomNextApiRequest = NextApiRequest & Request;
|
||||||
type CustomNextApiResponse = NextApiResponse & Response;
|
type CustomNextApiResponse = NextApiResponse & Response;
|
||||||
|
|
||||||
vi.mock("@calcom/lib/videoClient", () => {
|
vi.mock("@calcom/app-store/videoClient", () => {
|
||||||
return {
|
return {
|
||||||
getAllTranscriptsAccessLinkFromRoomName: vi.fn(),
|
getAllTranscriptsAccessLinkFromRoomName: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import prismock from "../../../../../../tests/libs/__mocks__/prisma";
|
|
||||||
|
|
||||||
import type { Request, Response } from "express";
|
import type { Request, Response } from "express";
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { createMocks } from "node-mocks-http";
|
import { createMocks } from "node-mocks-http";
|
||||||
import { describe, it, expect, test } from "vitest";
|
import { describe, it, expect, test, beforeAll, afterAll } from "vitest";
|
||||||
|
|
||||||
|
import { prisma } from "@calcom/prisma";
|
||||||
|
import type { User, Team, Prisma } from "@calcom/prisma/client";
|
||||||
import { MembershipRole } from "@calcom/prisma/enums";
|
import { MembershipRole } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
import authMiddleware from "../../../pages/api/bookings/[id]/_auth-middleware";
|
import authMiddleware from "../../../pages/api/bookings/[id]/_auth-middleware";
|
||||||
@@ -12,229 +12,206 @@ import authMiddleware from "../../../pages/api/bookings/[id]/_auth-middleware";
|
|||||||
type CustomNextApiRequest = NextApiRequest & Request;
|
type CustomNextApiRequest = NextApiRequest & Request;
|
||||||
type CustomNextApiResponse = NextApiResponse & Response;
|
type CustomNextApiResponse = NextApiResponse & Response;
|
||||||
|
|
||||||
|
const createEventTypeEventSelect = {
|
||||||
|
bookings: true,
|
||||||
|
} satisfies Prisma.EventTypeSelect;
|
||||||
|
|
||||||
describe("Booking ownership and access in Middleware", () => {
|
describe("Booking ownership and access in Middleware", () => {
|
||||||
const adminUserId = 1;
|
let adminUserRef: User;
|
||||||
const ownerUserId = 2;
|
let ownerUserRef: User;
|
||||||
const memberUserId = 3;
|
let orgOwnerUserRef: User;
|
||||||
const orgOwnerUserId = 4;
|
let memberUserRef: User;
|
||||||
const adminUserEmail = "admin@example.com";
|
let orgRef: Team;
|
||||||
const ownerUserEmail = "owner@example.com";
|
|
||||||
const memberUserEmail = "member@example.com";
|
let createEventResult1: Prisma.EventTypeGetPayload<{ select: typeof createEventTypeEventSelect }>;
|
||||||
const orgOwnerUserEmail = "org-owner@example.com";
|
let createEventResult2: Prisma.EventTypeGetPayload<{ select: typeof createEventTypeEventSelect }>;
|
||||||
|
|
||||||
// mock user data
|
// mock user data
|
||||||
function buildMockData() {
|
beforeAll(async () => {
|
||||||
//Create Users
|
//Create Users
|
||||||
prismock.user.create({
|
const createAdminUser = prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
id: adminUserId,
|
username: `admin-${Date.now()}`,
|
||||||
username: "admin",
|
|
||||||
name: "Admin User",
|
name: "Admin User",
|
||||||
email: adminUserEmail,
|
email: `admin+${Date.now()}@example.com`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
prismock.user.create({
|
const createOwnerUser = prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
id: ownerUserId,
|
username: `owner-${Date.now()}`,
|
||||||
username: "owner",
|
|
||||||
name: "Owner User",
|
name: "Owner User",
|
||||||
email: ownerUserEmail,
|
email: `owner+${Date.now()}@example.com`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
prismock.user.create({
|
const createOrgOwnerUser = prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
id: orgOwnerUserId,
|
username: `org-owner-${Date.now()}`,
|
||||||
username: "org-owner",
|
|
||||||
name: "Org Owner",
|
name: "Org Owner",
|
||||||
email: orgOwnerUserEmail,
|
email: `org-owner+${Date.now()}@example.com`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
prismock.user.create({
|
const createMemberUser = prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
id: memberUserId,
|
username: `member-${Date.now()}`,
|
||||||
username: "member",
|
|
||||||
name: "Member User",
|
name: "Member User",
|
||||||
email: memberUserEmail,
|
email: `member+${Date.now()}@example.com`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
[adminUserRef, ownerUserRef, orgOwnerUserRef, memberUserRef] = await Promise.all([
|
||||||
|
createAdminUser,
|
||||||
|
createOwnerUser,
|
||||||
|
createOrgOwnerUser,
|
||||||
|
createMemberUser,
|
||||||
|
]);
|
||||||
|
|
||||||
|
//create Org & Team
|
||||||
|
orgRef = await prisma.team.create({
|
||||||
|
data: {
|
||||||
|
name: "Org",
|
||||||
|
slug: `org-${Date.now()}`,
|
||||||
|
isOrganization: true,
|
||||||
|
children: {
|
||||||
|
create: {
|
||||||
|
name: "Team 1",
|
||||||
|
slug: `team1-${Date.now()}`,
|
||||||
|
members: {
|
||||||
|
createMany: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
userId: adminUserRef.id,
|
||||||
|
role: MembershipRole.ADMIN,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: ownerUserRef.id,
|
||||||
|
role: MembershipRole.OWNER,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: memberUserRef.id,
|
||||||
|
role: MembershipRole.MEMBER,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
members: {
|
||||||
|
createMany: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
userId: ownerUserRef.id,
|
||||||
|
role: MembershipRole.OWNER,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: memberUserRef.id,
|
||||||
|
role: MembershipRole.MEMBER,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: adminUserRef.id,
|
||||||
|
role: MembershipRole.MEMBER,
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//create eventTypes
|
||||||
|
const createEventTypeEvent1 = prisma.eventType.create({
|
||||||
|
data: {
|
||||||
|
title: "Event 1",
|
||||||
|
slug: `event-1-${Date.now()}`,
|
||||||
|
userId: ownerUserRef.id,
|
||||||
|
length: 60,
|
||||||
bookings: {
|
bookings: {
|
||||||
create: {
|
create: {
|
||||||
id: 2,
|
uid: `booking-2-${Date.now()}`,
|
||||||
uid: "2",
|
|
||||||
title: "Booking 2",
|
title: "Booking 2",
|
||||||
eventTypeId: 1,
|
userId: memberUserRef.id,
|
||||||
startTime: "2024-08-30T06:45:00.000Z",
|
startTime: "2024-08-30T06:45:00.000Z",
|
||||||
endTime: "2024-08-30T07:45:00.000Z",
|
endTime: "2024-08-30T07:45:00.000Z",
|
||||||
attendees: {
|
attendees: {
|
||||||
create: {
|
create: {
|
||||||
name: "Member User",
|
name: "Member User",
|
||||||
email: memberUserEmail,
|
email: memberUserRef.email,
|
||||||
timeZone: "UTC",
|
timeZone: "UTC",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
select: createEventTypeEventSelect,
|
||||||
});
|
});
|
||||||
//create team
|
const createEventTypeEvent2 = prisma.eventType.create({
|
||||||
prismock.team.create({
|
|
||||||
data: {
|
data: {
|
||||||
id: 1,
|
|
||||||
name: "Team 1",
|
|
||||||
slug: "team1",
|
|
||||||
members: {
|
|
||||||
createMany: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
userId: adminUserId,
|
|
||||||
role: MembershipRole.ADMIN,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: ownerUserId,
|
|
||||||
role: MembershipRole.OWNER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: memberUserId,
|
|
||||||
role: MembershipRole.MEMBER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//create Org
|
|
||||||
prismock.team.create({
|
|
||||||
data: {
|
|
||||||
id: 2,
|
|
||||||
name: "Org",
|
|
||||||
slug: "org",
|
|
||||||
isOrganization: true,
|
|
||||||
children: {
|
|
||||||
connect: {
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
members: {
|
|
||||||
createMany: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
userId: orgOwnerUserId,
|
|
||||||
role: MembershipRole.OWNER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: memberUserId,
|
|
||||||
role: MembershipRole.MEMBER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: ownerUserId,
|
|
||||||
role: MembershipRole.MEMBER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: adminUserId,
|
|
||||||
role: MembershipRole.MEMBER,
|
|
||||||
accepted: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//create eventTypes
|
|
||||||
prismock.eventType.create({
|
|
||||||
data: {
|
|
||||||
id: 1,
|
|
||||||
title: "Event 1",
|
|
||||||
slug: "event",
|
|
||||||
length: 60,
|
|
||||||
bookings: {
|
|
||||||
connect: {
|
|
||||||
id: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
prismock.eventType.create({
|
|
||||||
data: {
|
|
||||||
id: 2,
|
|
||||||
title: "Event 2",
|
title: "Event 2",
|
||||||
slug: "event",
|
slug: `event-2-${Date.now()}`,
|
||||||
length: 60,
|
length: 60,
|
||||||
teamId: 1,
|
teamId: orgRef.id,
|
||||||
bookings: {
|
bookings: {
|
||||||
connect: {
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//link eventType to teams
|
|
||||||
prismock.eventType.update({
|
|
||||||
where: {
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: ownerUserId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
prismock.eventType.update({
|
|
||||||
where: {
|
|
||||||
id: 2,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
team: {
|
|
||||||
connect: {
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//link team to org
|
|
||||||
prismock.team.update({
|
|
||||||
where: {
|
|
||||||
id: 1,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
parentId: 2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Call Prisma to create booking with attendees
|
|
||||||
prismock.booking.create({
|
|
||||||
data: {
|
|
||||||
id: 1,
|
|
||||||
uid: "1",
|
|
||||||
title: "Booking 1",
|
|
||||||
userId: 1,
|
|
||||||
startTime: "2024-08-30T06:45:00.000Z",
|
|
||||||
endTime: "2024-08-30T07:45:00.000Z",
|
|
||||||
eventTypeId: 2,
|
|
||||||
attendees: {
|
|
||||||
create: {
|
create: {
|
||||||
name: "Admin User",
|
uid: `booking-1-${Date.now()}`,
|
||||||
email: adminUserEmail,
|
title: "Booking 1",
|
||||||
timeZone: "UTC",
|
userId: adminUserRef.id,
|
||||||
|
startTime: "2024-08-30T06:45:00.000Z",
|
||||||
|
endTime: "2024-08-30T07:45:00.000Z",
|
||||||
|
attendees: {
|
||||||
|
create: {
|
||||||
|
name: "Admin User",
|
||||||
|
email: adminUserRef.email,
|
||||||
|
timeZone: "UTC",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
select: createEventTypeEventSelect,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
[createEventResult1, createEventResult2] = await Promise.all([
|
||||||
|
createEventTypeEvent1,
|
||||||
|
createEventTypeEvent2,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log("Cleaning up org", orgRef.id);
|
||||||
|
await prisma.team.delete({
|
||||||
|
where: {
|
||||||
|
id: orgRef.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log("Cleaning up users", [
|
||||||
|
adminUserRef.id,
|
||||||
|
ownerUserRef.id,
|
||||||
|
orgOwnerUserRef.id,
|
||||||
|
memberUserRef.id,
|
||||||
|
]);
|
||||||
|
await prisma.user.deleteMany({
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
in: [adminUserRef.id, ownerUserRef.id, orgOwnerUserRef.id, memberUserRef.id],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("should not throw error for bookings where user is an attendee", async () => {
|
test("should not throw error for bookings where user is an attendee", async () => {
|
||||||
|
console.log(createEventResult1.bookings[0].id);
|
||||||
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: {
|
query: {
|
||||||
id: 2,
|
id: createEventResult1.bookings[0].id,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req.userId = memberUserRef.id;
|
||||||
req.userId = memberUserId;
|
|
||||||
await expect(authMiddleware(req)).resolves.not.toThrow();
|
await expect(authMiddleware(req)).resolves.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,10 +221,9 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
query: {
|
query: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req.userId = memberUserRef.id;
|
||||||
req.userId = memberUserId;
|
|
||||||
|
|
||||||
await expect(authMiddleware(req)).rejects.toThrow();
|
await expect(authMiddleware(req)).rejects.toThrow();
|
||||||
});
|
});
|
||||||
@@ -256,12 +232,11 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: {
|
query: {
|
||||||
id: 2,
|
id: createEventResult2.bookings[0].id,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req.userId = ownerUserRef.id;
|
||||||
req.userId = ownerUserId;
|
|
||||||
await expect(authMiddleware(req)).resolves.not.toThrow();
|
await expect(authMiddleware(req)).resolves.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -269,21 +244,19 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
const { req: req1 } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req: req1 } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: {
|
query: {
|
||||||
id: 1,
|
id: createEventResult2.bookings[0].id,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
const { req: req2 } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req: req2 } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: {
|
query: {
|
||||||
id: 1,
|
id: createEventResult2.bookings[0].id,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req1.userId = adminUserRef.id;
|
||||||
|
req2.userId = ownerUserRef.id;
|
||||||
req1.userId = adminUserId;
|
|
||||||
req2.userId = ownerUserId;
|
|
||||||
|
|
||||||
await expect(authMiddleware(req1)).resolves.not.toThrow();
|
await expect(authMiddleware(req1)).resolves.not.toThrow();
|
||||||
await expect(authMiddleware(req2)).resolves.not.toThrow();
|
await expect(authMiddleware(req2)).resolves.not.toThrow();
|
||||||
@@ -292,13 +265,12 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: {
|
query: {
|
||||||
id: 1,
|
id: createEventResult2.bookings[0].id,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
|
||||||
|
|
||||||
req.userId = memberUserId;
|
req.userId = memberUserRef.id;
|
||||||
|
|
||||||
await expect(authMiddleware(req)).rejects.toThrow();
|
await expect(authMiddleware(req)).rejects.toThrow();
|
||||||
});
|
});
|
||||||
@@ -308,10 +280,9 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
query: {
|
query: {
|
||||||
id: 2,
|
id: 2,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req.userId = adminUserRef.id;
|
||||||
req.userId = adminUserId;
|
|
||||||
req.isSystemWideAdmin = true;
|
req.isSystemWideAdmin = true;
|
||||||
|
|
||||||
await authMiddleware(req);
|
await authMiddleware(req);
|
||||||
@@ -323,12 +294,11 @@ describe("Booking ownership and access in Middleware", () => {
|
|||||||
query: {
|
query: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
prisma: prismock,
|
prisma,
|
||||||
});
|
});
|
||||||
buildMockData();
|
req.userId = orgOwnerUserRef.id;
|
||||||
req.userId = orgOwnerUserId;
|
|
||||||
req.isOrganizationOwnerOrAdmin = true;
|
req.isOrganizationOwnerOrAdmin = true;
|
||||||
|
|
||||||
await authMiddleware(req);
|
await expect(authMiddleware(req)).rejects.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ vi.mock("@calcom/lib/di/containers/QualifiedHosts", () => ({
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("@calcom/lib/EventManager", () => ({
|
vi.mock("@calcom/features/bookings/lib/EventManager", () => ({
|
||||||
default: vi.fn().mockImplementation(() => ({
|
default: vi.fn().mockImplementation(() => ({
|
||||||
reschedule: vi.fn().mockResolvedValue({
|
reschedule: vi.fn().mockResolvedValue({
|
||||||
results: [],
|
results: [],
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ describe("DELETE /api/event-types/[id]", () => {
|
|||||||
|
|
||||||
describe("Error", async () => {
|
describe("Error", async () => {
|
||||||
test("Fails to remove event type if user is not OWNER/ADMIN of team associated with event type", async () => {
|
test("Fails to remove event type if user is not OWNER/ADMIN of team associated with event type", async () => {
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -71,15 +71,18 @@ describe("DELETE /api/event-types/[id]", () => {
|
|||||||
// Assign userId to the request objects
|
// Assign userId to the request objects
|
||||||
req.userId = memberUser;
|
req.userId = memberUser;
|
||||||
|
|
||||||
await handler(req, res);
|
await expect(handler(req)).rejects.toThrowError(
|
||||||
expect(res.statusCode).toBe(403); // Check if the deletion was successful
|
expect.objectContaining({
|
||||||
|
statusCode: 403,
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Success", async () => {
|
describe("Success", async () => {
|
||||||
test("Removes event type if user is owner of team associated with event type", async () => {
|
test("Removes event type if user is owner of team associated with event type", async () => {
|
||||||
// Mocks for DELETE request
|
// Mocks for DELETE request
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -90,8 +93,8 @@ describe("DELETE /api/event-types/[id]", () => {
|
|||||||
// Assign userId to the request objects
|
// Assign userId to the request objects
|
||||||
req.userId = adminUser;
|
req.userId = adminUser;
|
||||||
|
|
||||||
await handler(req, res);
|
const deletedEventType = await handler(req);
|
||||||
expect(res.statusCode).toBe(200); // Check if the deletion was successful
|
expect(deletedEventType).not.toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type CustomNextApiResponse = NextApiResponse & Response;
|
|||||||
describe("GET /api/event-types/[id]", () => {
|
describe("GET /api/event-types/[id]", () => {
|
||||||
describe("Errors", () => {
|
describe("Errors", () => {
|
||||||
test("Returns 403 if user not admin/team member/event owner", async () => {
|
test("Returns 403 if user not admin/team member/event owner", async () => {
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -32,16 +32,40 @@ describe("GET /api/event-types/[id]", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
req.userId = 333333;
|
req.userId = 333333;
|
||||||
await handler(req, res);
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(403);
|
await expect(handler(req)).rejects.toThrowError(
|
||||||
|
expect.objectContaining({
|
||||||
|
statusCode: 403,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test("Returns 404 if event type not found", async () => {
|
||||||
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
|
method: "GET",
|
||||||
|
body: {},
|
||||||
|
query: {
|
||||||
|
id: 123456,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
req.isSystemWideAdmin = true;
|
||||||
|
|
||||||
|
prismaMock.eventType.findUnique.mockResolvedValue(null);
|
||||||
|
|
||||||
|
req.userId = 333333;
|
||||||
|
|
||||||
|
await expect(handler(req)).rejects.toThrowError(
|
||||||
|
expect.objectContaining({
|
||||||
|
statusCode: 404,
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Success", async () => {
|
describe("Success", async () => {
|
||||||
test("Returns event type if user is admin", async () => {
|
test("Returns event type if user is admin", async () => {
|
||||||
const eventTypeId = 123456;
|
const eventTypeId = 123456;
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -57,17 +81,17 @@ describe("GET /api/event-types/[id]", () => {
|
|||||||
|
|
||||||
req.isSystemWideAdmin = true;
|
req.isSystemWideAdmin = true;
|
||||||
req.userId = 333333;
|
req.userId = 333333;
|
||||||
await handler(req, res);
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
const responseData = await handler(req);
|
||||||
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
|
|
||||||
|
expect(responseData.event_type.id).toEqual(eventTypeId);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Returns event type if user is in team associated with event type", async () => {
|
test("Returns event type if user is in team associated with event type", async () => {
|
||||||
const eventTypeId = 123456;
|
const eventTypeId = 123456;
|
||||||
const teamId = 9999;
|
const teamId = 9999;
|
||||||
const userId = 333333;
|
const userId = 333333;
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -94,10 +118,10 @@ describe("GET /api/event-types/[id]", () => {
|
|||||||
|
|
||||||
req.isSystemWideAdmin = false;
|
req.isSystemWideAdmin = false;
|
||||||
req.userId = userId;
|
req.userId = userId;
|
||||||
await handler(req, res);
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
const responseData = await handler(req);
|
||||||
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
|
|
||||||
|
expect(responseData.event_type.id).toEqual(eventTypeId);
|
||||||
expect(prismaMock.team.findFirst).toHaveBeenCalledWith({
|
expect(prismaMock.team.findFirst).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
id: teamId,
|
id: teamId,
|
||||||
@@ -116,7 +140,7 @@ describe("GET /api/event-types/[id]", () => {
|
|||||||
test("Returns event type if user is the event type owner", async () => {
|
test("Returns event type if user is the event type owner", async () => {
|
||||||
const eventTypeId = 123456;
|
const eventTypeId = 123456;
|
||||||
const userId = 333333;
|
const userId = 333333;
|
||||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
body: {},
|
body: {},
|
||||||
query: {
|
query: {
|
||||||
@@ -134,10 +158,10 @@ describe("GET /api/event-types/[id]", () => {
|
|||||||
|
|
||||||
req.isSystemWideAdmin = false;
|
req.isSystemWideAdmin = false;
|
||||||
req.userId = userId;
|
req.userId = userId;
|
||||||
await handler(req, res);
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
const responseData = await handler(req);
|
||||||
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
|
|
||||||
|
expect(responseData.event_type.id).toEqual(eventTypeId);
|
||||||
expect(prismaMock.team.findFirst).not.toHaveBeenCalled();
|
expect(prismaMock.team.findFirst).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ describe("POST /api/selected-calendars", () => {
|
|||||||
integration: "google",
|
integration: "google",
|
||||||
externalId: "ext123",
|
externalId: "ext123",
|
||||||
userId: 444444,
|
userId: 444444,
|
||||||
id: "xxx-xxx",
|
id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
||||||
eventTypeId: null,
|
eventTypeId: null,
|
||||||
delegationCredentialId: null,
|
delegationCredentialId: null,
|
||||||
domainWideDelegationCredentialId: null,
|
domainWideDelegationCredentialId: null,
|
||||||
@@ -120,7 +120,7 @@ describe("POST /api/selected-calendars", () => {
|
|||||||
req.userId = 333333;
|
req.userId = 333333;
|
||||||
|
|
||||||
prismaMock.selectedCalendar.create.mockResolvedValue({
|
prismaMock.selectedCalendar.create.mockResolvedValue({
|
||||||
id: "xxx-xxx",
|
id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
||||||
credentialId: 1,
|
credentialId: 1,
|
||||||
integration: "google",
|
integration: "google",
|
||||||
externalId: "ext123",
|
externalId: "ext123",
|
||||||
|
|||||||
@@ -41,4 +41,5 @@ lerna-debug.log*
|
|||||||
.env.production.local
|
.env.production.local
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
!.env.appStore.example
|
!.env.appStore.example
|
||||||
|
/client/*
|
||||||
@@ -22,6 +22,8 @@ RUN yarn workspace @calcom/api-v2 run generate-schemas
|
|||||||
RUN rm -rf apps/api/v2/node_modules
|
RUN rm -rf apps/api/v2/node_modules
|
||||||
RUN yarn install
|
RUN yarn install
|
||||||
|
|
||||||
|
RUN yarn workspace @calcom/platform-libraries run build
|
||||||
|
|
||||||
RUN yarn workspace @calcom/api-v2 run build
|
RUN yarn workspace @calcom/api-v2 run build
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"@axiomhq/winston": "^1.2.0",
|
"@axiomhq/winston": "^1.2.0",
|
||||||
"@calcom/platform-constants": "*",
|
"@calcom/platform-constants": "*",
|
||||||
"@calcom/platform-enums": "*",
|
"@calcom/platform-enums": "*",
|
||||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.351",
|
"@calcom/platform-libraries": "*",
|
||||||
"@calcom/platform-types": "*",
|
"@calcom/platform-types": "*",
|
||||||
"@calcom/platform-utils": "*",
|
"@calcom/platform-utils": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { UserRepositoryFixture } from "test/fixtures/repository/users.repository
|
|||||||
import { randomString } from "test/utils/randomString";
|
import { randomString } from "test/utils/randomString";
|
||||||
|
|
||||||
import { X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
import { X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
||||||
import { User, PlatformOAuthClient, Team, RateLimit } from "@calcom/prisma/client";
|
import type { User, PlatformOAuthClient, Team, RateLimit } from "@calcom/prisma/client";
|
||||||
|
|
||||||
describe("AppController", () => {
|
describe("AppController", () => {
|
||||||
describe("Rate limiting", () => {
|
describe("Rate limiting", () => {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repo
|
|||||||
import { OAuthClientUsersService } from "@/modules/oauth-clients/services/oauth-clients-users.service";
|
import { OAuthClientUsersService } from "@/modules/oauth-clients/services/oauth-clients-users.service";
|
||||||
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
|
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
|
||||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||||
|
import { ProfilesModule } from "@/modules/profiles/profiles.module";
|
||||||
import { RedisModule } from "@/modules/redis/redis.module";
|
import { RedisModule } from "@/modules/redis/redis.module";
|
||||||
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
|
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
|
||||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||||
@@ -33,6 +34,7 @@ import { Module } from "@nestjs/common";
|
|||||||
EventTypesModule_2024_04_15,
|
EventTypesModule_2024_04_15,
|
||||||
SchedulesModule_2024_04_15,
|
SchedulesModule_2024_04_15,
|
||||||
EventTypesModule_2024_06_14,
|
EventTypesModule_2024_06_14,
|
||||||
|
ProfilesModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
TokensRepository,
|
TokensRepository,
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/
|
|||||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
|
||||||
import { UsersModule } from "@/modules/users/users.module";
|
import { UsersModule } from "@/modules/users/users.module";
|
||||||
import { INestApplication } from "@nestjs/common";
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import { User } from "@prisma/client";
|
|
||||||
import * as request from "supertest";
|
import * as request from "supertest";
|
||||||
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
||||||
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
||||||
@@ -22,9 +20,10 @@ import { UserRepositoryFixture } from "test/fixtures/repository/users.repository
|
|||||||
import { randomString } from "test/utils/randomString";
|
import { randomString } from "test/utils/randomString";
|
||||||
import { withApiAuth } from "test/utils/withApiAuth";
|
import { withApiAuth } from "test/utils/withApiAuth";
|
||||||
|
|
||||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||||
import { handleNewBooking } from "@calcom/platform-libraries";
|
import { handleNewBooking } from "@calcom/platform-libraries";
|
||||||
import { ApiSuccessResponse, ApiResponse, ApiErrorResponse } from "@calcom/platform-types";
|
import type { ApiSuccessResponse, ApiErrorResponse } from "@calcom/platform-types";
|
||||||
|
import type { User } from "@calcom/prisma/client";
|
||||||
|
|
||||||
describe("Bookings Endpoints 2024-04-15", () => {
|
describe("Bookings Endpoints 2024-04-15", () => {
|
||||||
describe("User Authenticated", () => {
|
describe("User Authenticated", () => {
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ import {
|
|||||||
CancelBookingInput_2024_04_15,
|
CancelBookingInput_2024_04_15,
|
||||||
Status_2024_04_15,
|
Status_2024_04_15,
|
||||||
} from "@calcom/platform-types";
|
} from "@calcom/platform-types";
|
||||||
import { ApiResponse } from "@calcom/platform-types";
|
import type { ApiResponse } from "@calcom/platform-types";
|
||||||
import { PrismaClient } from "@calcom/prisma";
|
import type { PrismaClient } from "@calcom/prisma";
|
||||||
|
|
||||||
type BookingRequest = Request & {
|
type BookingRequest = Request & {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,6 @@ import { UsersModule } from "@/modules/users/users.module";
|
|||||||
import { INestApplication } from "@nestjs/common";
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import { PlatformOAuthClient, Team, User } from "@prisma/client";
|
|
||||||
import * as request from "supertest";
|
import * as request from "supertest";
|
||||||
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
|
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
|
||||||
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
|
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
|
||||||
@@ -33,6 +32,7 @@ import {
|
|||||||
CreateEventTypeInput_2024_06_14,
|
CreateEventTypeInput_2024_06_14,
|
||||||
EventTypeOutput_2024_06_14,
|
EventTypeOutput_2024_06_14,
|
||||||
} from "@calcom/platform-types";
|
} from "@calcom/platform-types";
|
||||||
|
import type { PlatformOAuthClient, Team, User } from "@calcom/prisma/client";
|
||||||
|
|
||||||
const CLIENT_REDIRECT_URI = "http://localhost:4321";
|
const CLIENT_REDIRECT_URI = "http://localhost:4321";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { BookingReferencesFilterInput_2024_08_13 } from "@/ee/bookings/2024-08-13/inputs/booking-references-filter.input";
|
import { BookingReferencesFilterInput_2024_08_13 } from "@/ee/bookings/2024-08-13/inputs/booking-references-filter.input";
|
||||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BookingReferencesRepository_2024_08_13 {
|
export class BookingReferencesRepository_2024_08_13 {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.se
|
|||||||
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
|
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
|
||||||
import { OrganizationsTeamsRepository } from "@/modules/organizations/teams/index/organizations-teams.repository";
|
import { OrganizationsTeamsRepository } from "@/modules/organizations/teams/index/organizations-teams.repository";
|
||||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||||
|
import { ProfilesModule } from "@/modules/profiles/profiles.module";
|
||||||
import { RedisModule } from "@/modules/redis/redis.module";
|
import { RedisModule } from "@/modules/redis/redis.module";
|
||||||
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
|
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
|
||||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||||
@@ -56,6 +57,7 @@ import { Module } from "@nestjs/common";
|
|||||||
TeamsModule,
|
TeamsModule,
|
||||||
TeamsEventTypesModule,
|
TeamsEventTypesModule,
|
||||||
MembershipsModule,
|
MembershipsModule,
|
||||||
|
ProfilesModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
TokensRepository,
|
TokensRepository,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import type { Prisma } from "@prisma/client";
|
|
||||||
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BookingsRepository_2024_08_13 {
|
export class BookingsRepository_2024_08_13 {
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ import { BookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08-13/se
|
|||||||
import { BookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/bookings.service";
|
import { BookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/bookings.service";
|
||||||
import { CalVideoService } from "@/ee/bookings/2024-08-13/services/cal-video.service";
|
import { CalVideoService } from "@/ee/bookings/2024-08-13/services/cal-video.service";
|
||||||
import { VERSION_2024_08_13_VALUE, VERSION_2024_08_13 } from "@/lib/api-versions";
|
import { VERSION_2024_08_13_VALUE, VERSION_2024_08_13 } from "@/lib/api-versions";
|
||||||
import { API_KEY_OR_ACCESS_TOKEN_HEADER } from "@/lib/docs/headers";
|
import {
|
||||||
|
API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||||
|
OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER,
|
||||||
|
OPTIONAL_X_CAL_CLIENT_ID_HEADER,
|
||||||
|
OPTIONAL_X_CAL_SECRET_KEY_HEADER,
|
||||||
|
} from "@/lib/docs/headers";
|
||||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||||
import {
|
import {
|
||||||
AuthOptionalUser,
|
AuthOptionalUser,
|
||||||
@@ -22,8 +27,8 @@ import { Permissions } from "@/modules/auth/decorators/permissions/permissions.d
|
|||||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||||
import { OptionalApiAuthGuard } from "@/modules/auth/guards/optional-api-auth/optional-api-auth.guard";
|
import { OptionalApiAuthGuard } from "@/modules/auth/guards/optional-api-auth/optional-api-auth.guard";
|
||||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||||
|
import { ApiAuthGuardUser } from "@/modules/auth/strategies/api-auth/api-auth.strategy";
|
||||||
import { UsersService } from "@/modules/users/services/users.service";
|
import { UsersService } from "@/modules/users/services/users.service";
|
||||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
Post,
|
Post,
|
||||||
@@ -101,6 +106,9 @@ export class BookingsController_2024_08_13 {
|
|||||||
|
|
||||||
@Post("/")
|
@Post("/")
|
||||||
@UseGuards(OptionalApiAuthGuard)
|
@UseGuards(OptionalApiAuthGuard)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Create a booking",
|
summary: "Create a booking",
|
||||||
description: `
|
description: `
|
||||||
@@ -122,6 +130,9 @@ export class BookingsController_2024_08_13 {
|
|||||||
And 2 ways to book and event type belonging to a team:
|
And 2 ways to book and event type belonging to a team:
|
||||||
1. Provide \`eventTypeId\` in the request body.
|
1. Provide \`eventTypeId\` in the request body.
|
||||||
2. Provide \`eventTypeSlug\` and \`teamSlug\` and optionally \`organizationSlug\` if the team with the teamSlug is within an organization.
|
2. Provide \`eventTypeSlug\` and \`teamSlug\` and optionally \`organizationSlug\` if the team with the teamSlug is within an organization.
|
||||||
|
|
||||||
|
If you are creating a seated booking for an event type with 'show attendees' disabled, then to retrieve attendees in the response either set 'show attendees' to true on event type level or
|
||||||
|
you have to provide an authentication method of event type owner, host, team admin or owner or org admin or owner.
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
@ApiBody({
|
@ApiBody({
|
||||||
@@ -161,7 +172,10 @@ export class BookingsController_2024_08_13 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get("/:bookingUid")
|
@Get("/:bookingUid")
|
||||||
@UseGuards(BookingUidGuard)
|
@UseGuards(BookingUidGuard, OptionalApiAuthGuard)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Get a booking",
|
summary: "Get a booking",
|
||||||
description: `\`:bookingUid\` can be
|
description: `\`:bookingUid\` can be
|
||||||
@@ -170,10 +184,17 @@ export class BookingsController_2024_08_13 {
|
|||||||
|
|
||||||
2. uid of one of the recurring booking recurrences
|
2. uid of one of the recurring booking recurrences
|
||||||
|
|
||||||
3. uid of recurring booking which will return an array of all recurring booking recurrences (stored as recurringBookingUid on one of the individual recurrences).`,
|
3. uid of recurring booking which will return an array of all recurring booking recurrences (stored as recurringBookingUid on one of the individual recurrences).
|
||||||
|
|
||||||
|
If you are fetching a seated booking for an event type with 'show attendees' disabled, then to retrieve attendees in the response either set 'show attendees' to true on event type level or
|
||||||
|
you have to provide an authentication method of event type owner, host, team admin or owner or org admin or owner.
|
||||||
|
`,
|
||||||
})
|
})
|
||||||
async getBooking(@Param("bookingUid") bookingUid: string): Promise<GetBookingOutput_2024_08_13> {
|
async getBooking(
|
||||||
const booking = await this.bookingsService.getBooking(bookingUid);
|
@Param("bookingUid") bookingUid: string,
|
||||||
|
@GetOptionalUser() user: AuthOptionalUser
|
||||||
|
): Promise<GetBookingOutput_2024_08_13> {
|
||||||
|
const booking = await this.bookingsService.getBooking(bookingUid, user);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: SUCCESS_STATUS,
|
status: SUCCESS_STATUS,
|
||||||
@@ -218,7 +239,7 @@ export class BookingsController_2024_08_13 {
|
|||||||
@ApiOperation({ summary: "Get all bookings" })
|
@ApiOperation({ summary: "Get all bookings" })
|
||||||
async getBookings(
|
async getBookings(
|
||||||
@Query() queryParams: GetBookingsInput_2024_08_13,
|
@Query() queryParams: GetBookingsInput_2024_08_13,
|
||||||
@GetUser() user: UserWithProfile
|
@GetUser() user: ApiAuthGuardUser
|
||||||
): Promise<GetBookingsOutput_2024_08_13> {
|
): Promise<GetBookingsOutput_2024_08_13> {
|
||||||
const profile = this.usersService.getUserMainProfile(user);
|
const profile = this.usersService.getUserMainProfile(user);
|
||||||
|
|
||||||
@@ -236,7 +257,10 @@ export class BookingsController_2024_08_13 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post("/:bookingUid/reschedule")
|
@Post("/:bookingUid/reschedule")
|
||||||
@UseGuards(BookingUidGuard)
|
@UseGuards(BookingUidGuard, OptionalApiAuthGuard)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Reschedule a booking",
|
summary: "Reschedule a booking",
|
||||||
description: "Reschedule a booking or seated booking",
|
description: "Reschedule a booking or seated booking",
|
||||||
@@ -248,17 +272,20 @@ export class BookingsController_2024_08_13 {
|
|||||||
{ $ref: getSchemaPath(RescheduleSeatedBookingInput_2024_08_13) },
|
{ $ref: getSchemaPath(RescheduleSeatedBookingInput_2024_08_13) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
description:
|
description: `Accepts different types of reschedule booking input: Reschedule Booking (Option 1) or Reschedule Seated Booking (Option 2).
|
||||||
"Accepts different types of reschedule booking input: Reschedule Booking (Option 1) or Reschedule Seated Booking (Option 2)",
|
|
||||||
|
If you are rescheduling a seated booking for an event type with 'show attendees' disabled, then to retrieve attendees in the response either set 'show attendees' to true on event type level or
|
||||||
|
you have to provide an authentication method of event type owner, host, team admin or owner or org admin or owner.`,
|
||||||
})
|
})
|
||||||
@ApiExtraModels(RescheduleBookingInput_2024_08_13, RescheduleSeatedBookingInput_2024_08_13)
|
@ApiExtraModels(RescheduleBookingInput_2024_08_13, RescheduleSeatedBookingInput_2024_08_13)
|
||||||
async rescheduleBooking(
|
async rescheduleBooking(
|
||||||
@Param("bookingUid") bookingUid: string,
|
@Param("bookingUid") bookingUid: string,
|
||||||
@Body(new RescheduleBookingInputPipe())
|
@Body(new RescheduleBookingInputPipe())
|
||||||
body: RescheduleBookingInput,
|
body: RescheduleBookingInput,
|
||||||
@Req() request: Request
|
@Req() request: Request,
|
||||||
|
@GetOptionalUser() user: AuthOptionalUser
|
||||||
): Promise<RescheduleBookingOutput_2024_08_13> {
|
): Promise<RescheduleBookingOutput_2024_08_13> {
|
||||||
const newBooking = await this.bookingsService.rescheduleBooking(request, bookingUid, body);
|
const newBooking = await this.bookingsService.rescheduleBooking(request, bookingUid, body, user);
|
||||||
await this.bookingsService.billRescheduledBooking(newBooking, bookingUid);
|
await this.bookingsService.billRescheduledBooking(newBooking, bookingUid);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -268,7 +295,10 @@ export class BookingsController_2024_08_13 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post("/:bookingUid/cancel")
|
@Post("/:bookingUid/cancel")
|
||||||
@UseGuards(BookingUidGuard)
|
@UseGuards(BookingUidGuard, OptionalApiAuthGuard)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_CLIENT_ID_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_X_CAL_SECRET_KEY_HEADER)
|
||||||
|
@ApiHeader(OPTIONAL_API_KEY_OR_ACCESS_TOKEN_HEADER)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Cancel a booking",
|
summary: "Cancel a booking",
|
||||||
@@ -281,7 +311,11 @@ export class BookingsController_2024_08_13 {
|
|||||||
|
|
||||||
\nCancelling recurring seated bookings:
|
\nCancelling recurring seated bookings:
|
||||||
For recurring seated bookings it is not possible to cancel all of them with 1 call
|
For recurring seated bookings it is not possible to cancel all of them with 1 call
|
||||||
like with non-seated recurring bookings by providing recurring bookind uid - you have to cancel each recurrence booking by its bookingUid + seatUid.`,
|
like with non-seated recurring bookings by providing recurring bookind uid - you have to cancel each recurrence booking by its bookingUid + seatUid.
|
||||||
|
|
||||||
|
If you are cancelling a seated booking for an event type with 'show attendees' disabled, then to retrieve attendees in the response either set 'show attendees' to true on event type level or
|
||||||
|
you have to provide an authentication method of event type owner, host, team admin or owner or org admin or owner.
|
||||||
|
`,
|
||||||
})
|
})
|
||||||
@ApiBody({
|
@ApiBody({
|
||||||
schema: {
|
schema: {
|
||||||
@@ -298,9 +332,10 @@ export class BookingsController_2024_08_13 {
|
|||||||
@Req() request: Request,
|
@Req() request: Request,
|
||||||
@Param("bookingUid") bookingUid: string,
|
@Param("bookingUid") bookingUid: string,
|
||||||
@Body(new CancelBookingInputPipe())
|
@Body(new CancelBookingInputPipe())
|
||||||
body: CancelBookingInput
|
body: CancelBookingInput,
|
||||||
|
@GetOptionalUser() user: AuthOptionalUser
|
||||||
): Promise<CancelBookingOutput_2024_08_13> {
|
): Promise<CancelBookingOutput_2024_08_13> {
|
||||||
const cancelledBooking = await this.bookingsService.cancelBooking(request, bookingUid, body);
|
const cancelledBooking = await this.bookingsService.cancelBooking(request, bookingUid, body, user);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: SUCCESS_STATUS,
|
status: SUCCESS_STATUS,
|
||||||
@@ -342,7 +377,7 @@ export class BookingsController_2024_08_13 {
|
|||||||
})
|
})
|
||||||
async reassignBooking(
|
async reassignBooking(
|
||||||
@Param("bookingUid") bookingUid: string,
|
@Param("bookingUid") bookingUid: string,
|
||||||
@GetUser() user: UserWithProfile
|
@GetUser() user: ApiAuthGuardUser
|
||||||
): Promise<ReassignBookingOutput_2024_08_13> {
|
): Promise<ReassignBookingOutput_2024_08_13> {
|
||||||
const booking = await this.bookingsService.reassignBooking(bookingUid, user);
|
const booking = await this.bookingsService.reassignBooking(bookingUid, user);
|
||||||
|
|
||||||
@@ -392,7 +427,7 @@ export class BookingsController_2024_08_13 {
|
|||||||
})
|
})
|
||||||
async confirmBooking(
|
async confirmBooking(
|
||||||
@Param("bookingUid") bookingUid: string,
|
@Param("bookingUid") bookingUid: string,
|
||||||
@GetUser() user: UserWithProfile
|
@GetUser() user: ApiAuthGuardUser
|
||||||
): Promise<GetBookingOutput_2024_08_13> {
|
): Promise<GetBookingOutput_2024_08_13> {
|
||||||
const booking = await this.bookingsService.confirmBooking(bookingUid, user);
|
const booking = await this.bookingsService.confirmBooking(bookingUid, user);
|
||||||
|
|
||||||
@@ -414,7 +449,7 @@ export class BookingsController_2024_08_13 {
|
|||||||
async declineBooking(
|
async declineBooking(
|
||||||
@Param("bookingUid") bookingUid: string,
|
@Param("bookingUid") bookingUid: string,
|
||||||
@Body() body: DeclineBookingInput_2024_08_13,
|
@Body() body: DeclineBookingInput_2024_08_13,
|
||||||
@GetUser() user: UserWithProfile
|
@GetUser() user: ApiAuthGuardUser
|
||||||
): Promise<GetBookingOutput_2024_08_13> {
|
): Promise<GetBookingOutput_2024_08_13> {
|
||||||
const booking = await this.bookingsService.declineBooking(bookingUid, user, body.reason);
|
const booking = await this.bookingsService.declineBooking(bookingUid, user, body.reason);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { UsersModule } from "@/modules/users/users.module";
|
|||||||
import { INestApplication } from "@nestjs/common";
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import { User } from "@prisma/client";
|
|
||||||
import * as request from "supertest";
|
import * as request from "supertest";
|
||||||
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
||||||
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
||||||
@@ -37,7 +36,7 @@ import {
|
|||||||
RescheduleBookingInput_2024_08_13,
|
RescheduleBookingInput_2024_08_13,
|
||||||
CancelBookingInput_2024_08_13,
|
CancelBookingInput_2024_08_13,
|
||||||
} from "@calcom/platform-types";
|
} from "@calcom/platform-types";
|
||||||
import { Team } from "@calcom/prisma/client";
|
import type { User, Team } from "@calcom/prisma/client";
|
||||||
|
|
||||||
jest.spyOn(AttendeeScheduledEmail.prototype as any, "getHtml").mockImplementation(async function () {
|
jest.spyOn(AttendeeScheduledEmail.prototype as any, "getHtml").mockImplementation(async function () {
|
||||||
return "<html><body>Mocked Email Content</body></html>";
|
return "<html><body>Mocked Email Content</body></html>";
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
GetSeatedBookingOutput_2024_08_13,
|
GetSeatedBookingOutput_2024_08_13,
|
||||||
} from "@calcom/platform-types";
|
} from "@calcom/platform-types";
|
||||||
import { BookingOutput_2024_08_13 } from "@calcom/platform-types";
|
import { BookingOutput_2024_08_13 } from "@calcom/platform-types";
|
||||||
import { Booking, PlatformOAuthClient, Team, User, EventType } from "@calcom/prisma/client";
|
import type { Booking, PlatformOAuthClient, Team, User, EventType } from "@calcom/prisma/client";
|
||||||
|
|
||||||
describe("Bookings Endpoints 2024-08-13", () => {
|
describe("Bookings Endpoints 2024-08-13", () => {
|
||||||
describe("Booking fields", () => {
|
describe("Booking fields", () => {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { UsersModule } from "@/modules/users/users.module";
|
|||||||
import { INestApplication } from "@nestjs/common";
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import { User } from "@prisma/client";
|
|
||||||
import * as request from "supertest";
|
import * as request from "supertest";
|
||||||
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
||||||
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
||||||
@@ -20,7 +19,7 @@ import { randomString } from "test/utils/randomString";
|
|||||||
import { withApiAuth } from "test/utils/withApiAuth";
|
import { withApiAuth } from "test/utils/withApiAuth";
|
||||||
|
|
||||||
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
|
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
|
||||||
import { Booking, PlatformOAuthClient, Team } from "@calcom/prisma/client";
|
import type { User, Booking, PlatformOAuthClient, Team } from "@calcom/prisma/client";
|
||||||
|
|
||||||
describe("Bookings Endpoints 2024-08-13", () => {
|
describe("Bookings Endpoints 2024-08-13", () => {
|
||||||
describe("Calendar Links", () => {
|
describe("Calendar Links", () => {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { UsersModule } from "@/modules/users/users.module";
|
|||||||
import { INestApplication } from "@nestjs/common";
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import { User } from "@prisma/client";
|
|
||||||
import * as request from "supertest";
|
import * as request from "supertest";
|
||||||
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
|
||||||
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
||||||
@@ -21,7 +20,7 @@ import { withApiAuth } from "test/utils/withApiAuth";
|
|||||||
|
|
||||||
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
|
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
|
||||||
import { BookingOutput_2024_08_13, GetBookingOutput_2024_08_13 } from "@calcom/platform-types";
|
import { BookingOutput_2024_08_13, GetBookingOutput_2024_08_13 } from "@calcom/platform-types";
|
||||||
import { Booking, PlatformOAuthClient, Team } from "@calcom/prisma/client";
|
import type { User, Booking, PlatformOAuthClient, Team } from "@calcom/prisma/client";
|
||||||
|
|
||||||
describe("Bookings Endpoints 2024-08-13", () => {
|
describe("Bookings Endpoints 2024-08-13", () => {
|
||||||
describe("Bookings confirmation", () => {
|
describe("Bookings confirmation", () => {
|
||||||
@@ -40,7 +39,6 @@ describe("Bookings Endpoints 2024-08-13", () => {
|
|||||||
let user: User;
|
let user: User;
|
||||||
|
|
||||||
let eventTypeId: number;
|
let eventTypeId: number;
|
||||||
const eventTypeSlug = `confirm-bookings-2024-08-13-event-type-${randomString()}`;
|
|
||||||
|
|
||||||
let createdBooking1: Booking;
|
let createdBooking1: Booking;
|
||||||
let createdBooking2: Booking;
|
let createdBooking2: Booking;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user