rebase fixing conflicts
parent
11e1312e3a
commit
9a5c3f96ec
|
@ -0,0 +1,6 @@
|
|||
NEXTAUTH_URL=http://localhost:3000 // This requires you run also app.cal.com in localhost:3000 to re-use it's Next-Auth api endpoints.
|
||||
NEXTAUTH_SECRET=hello
|
||||
EMAIL_SERVER='smtp://localhost:587'
|
||||
EMAIL_FROM=Cal.com <noreply@example.com>
|
||||
|
||||
DATABASE_URL="postgresql://postgres:@localhost:5450/calendso"
|
|
@ -1,4 +1,10 @@
|
|||
dist
|
||||
node_modules/
|
||||
.env
|
||||
<<<<<<< HEAD
|
||||
.next
|
||||
=======
|
||||
.next/
|
||||
.turbo/
|
||||
.tsconfig.tsbuildinfo
|
||||
>>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks)
|
||||
|
|
105
README.md
105
README.md
|
@ -1 +1,106 @@
|
|||
<<<<<<< HEAD
|
||||
# Cal.com Public API (Enterprise Only)
|
||||
=======
|
||||
# Public API for Cal.com
|
||||
|
||||
## This will be the new public enterprise-only API
|
||||
|
||||
It will be a REST API for now, we might want to look into adding a GraphQL endpoint way down the roadmap if it makes sense. For now we think REST should cover what developers need.
|
||||
|
||||
## NextJS + TypeScript
|
||||
|
||||
It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder.
|
||||
|
||||
## NextAuth
|
||||
|
||||
Using the new next-auth middleware getToken and getSession for our API auth and any other middleware check we might want to do like user role. enterprise status, api req limit, etc.
|
||||
|
||||
The idea is to leverage current `Session` accessToken. next-auth reads the Authorization Header and if it contains a valid JWT Bearer Token, it decodes it.
|
||||
|
||||
We'll also need the EmailProvider (to expose VerificationTokens generation) and prisma adapter (to connect with the database)
|
||||
We will extend it to also be valids PAT's with longer than web auth sessions expiryDates (maybe never expire).
|
||||
|
||||
## No react
|
||||
|
||||
It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like:
|
||||
|
||||
- `v1.api.cal.com`
|
||||
- `api.cal.com/v1`
|
||||
- `app.cal.com/api/v1/`
|
||||
|
||||
## Example
|
||||
|
||||
HTTP Request (Use Paw.app/postman/postwoman/hoppscotch)
|
||||
|
||||
```
|
||||
POST /api/jwt HTTP/1.1
|
||||
authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ
|
||||
```
|
||||
|
||||
or with cURL
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:3002/api/jwt" \
|
||||
-H 'authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ'
|
||||
```
|
||||
|
||||
Returns:
|
||||
|
||||
```{
|
||||
"name": null,
|
||||
"email": "m@n.es",
|
||||
"sub": "cl032mhik0006w4ylrtay2t3f",
|
||||
"iat": 1645894473,
|
||||
"exp": 1648486473,
|
||||
"jti": "af1c04f2-09a8-45b5-a6f0-c35eea9efa9b",
|
||||
"userRole": "admin"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API Endpoint Validation
|
||||
|
||||
The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
|
||||
|
||||
/event-types
|
||||
GET
|
||||
/teams
|
||||
teams/join
|
||||
|
||||
GET / PATCH / PUT /users/:id
|
||||
|
||||
/users/new
|
||||
POST
|
||||
/event-types
|
||||
/bookings
|
||||
/availabilties
|
||||
/schedules
|
||||
|
||||
## Users
|
||||
|
||||
GET /users : Get all users you're an owner / team manager of. Requires Auth.
|
||||
POST /users : Create a new user
|
||||
GET /users/{id} : Get the user information identified by "id"
|
||||
PUT /users/{id} : Update the user information identified by "id"
|
||||
DELETE /users/{id} : Delete user by "id"
|
||||
|
||||
## Event Types
|
||||
|
||||
/event-types
|
||||
GET /event-types : Get all event-types
|
||||
POST /event-types : Create a new user
|
||||
GET /event-types/{id} : Get the user information identified by "id"
|
||||
PUT /event-types/{id} : Update the user information identified by "id"
|
||||
DELETE /event-types/{id} : Delete user by "id"
|
||||
|
||||
## Bookings
|
||||
|
||||
/bookings
|
||||
>>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { createMocks } from "node-mocks-http";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
import { EventType } from "@calcom/prisma/client";
|
||||
|
||||
import handleEvent from "../pages/api/event-types/[id]";
|
||||
|
||||
describe("/api/event-types/[id]", () => {
|
||||
it("returns a message with the specified events", async () => {
|
||||
const { req, res } = createMocks({
|
||||
method: "GET",
|
||||
query: {
|
||||
id: 1,
|
||||
},
|
||||
});
|
||||
prisma.eventType.findUnique({ where: { id: 1 } }).then(async (data: EventType) => {
|
||||
await handleEvent(req, res);
|
||||
expect(res._getStatusCode()).toBe(200);
|
||||
expect(JSON.parse(res._getData())).toStrictEqual({ event: data });
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
|
||||
};
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* For a detailed explanation regarding each configuration property and type check, visit:
|
||||
* https://jestjs.io/docs/en/configuration.html
|
||||
*/
|
||||
|
||||
export default {
|
||||
// All imported modules in your tests should be mocked automatically
|
||||
// automock: false,
|
||||
|
||||
// Stop running tests after `n` failures
|
||||
// bail: 0,
|
||||
|
||||
// The directory where Jest should store its cached dependency information
|
||||
// cacheDirectory: "/private/var/folders/fl/sw088bcs0dx4zyy0f_ghzvwc0000gn/T/jest_dx",
|
||||
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
// Indicates whether the coverage information should be collected while executing the test
|
||||
// collectCoverage: false,
|
||||
|
||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||
// collectCoverageFrom: undefined,
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: "coverage",
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
// coveragePathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// Indicates which provider should be used to instrument code for coverage
|
||||
// coverageProvider: "babel",
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
// coverageReporters: [
|
||||
// "json",
|
||||
// "text",
|
||||
// "lcov",
|
||||
// "clover"
|
||||
// ],
|
||||
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
// coverageThreshold: undefined,
|
||||
|
||||
// A path to a custom dependency extractor
|
||||
// dependencyExtractor: undefined,
|
||||
|
||||
// Make calling deprecated APIs throw helpful error messages
|
||||
// errorOnDeprecated: false,
|
||||
|
||||
// Force coverage collection from ignored files using an array of glob patterns
|
||||
// forceCoverageMatch: [],
|
||||
|
||||
// A path to a module which exports an async function that is triggered once before all test suites
|
||||
// globalSetup: undefined,
|
||||
|
||||
// A path to a module which exports an async function that is triggered once after all test suites
|
||||
// globalTeardown: undefined,
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
// globals: {},
|
||||
|
||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||
// maxWorkers: "50%",
|
||||
|
||||
// An array of directory names to be searched recursively up from the requiring module's location
|
||||
// moduleDirectories: [
|
||||
// "node_modules"
|
||||
// ],
|
||||
|
||||
// An array of file extensions your modules use
|
||||
// moduleFileExtensions: [
|
||||
// "js",
|
||||
// "json",
|
||||
// "jsx",
|
||||
// "ts",
|
||||
// "tsx",
|
||||
// "node"
|
||||
// ],
|
||||
|
||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||
// moduleNameMapper: {},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
// modulePathIgnorePatterns: [],
|
||||
|
||||
// Activates notifications for test results
|
||||
// notify: false,
|
||||
|
||||
// An enum that specifies notification mode. Requires { notify: true }
|
||||
// notifyMode: "failure-change",
|
||||
|
||||
// A preset that is used as a base for Jest's configuration
|
||||
// preset: undefined,
|
||||
|
||||
// Run tests from one or more projects
|
||||
// projects: undefined,
|
||||
|
||||
// Use this configuration option to add custom reporters to Jest
|
||||
// reporters: undefined,
|
||||
|
||||
// Automatically reset mock state between every test
|
||||
// resetMocks: false,
|
||||
|
||||
// Reset the module registry before running each individual test
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
// resolver: undefined,
|
||||
|
||||
// Automatically restore mock state between every test
|
||||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
// rootDir: undefined,
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
// roots: [
|
||||
// "<rootDir>"
|
||||
// ],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||
// setupFiles: [],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||
// snapshotSerializers: [],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
testEnvironment: "node",
|
||||
|
||||
// Options that will be passed to the testEnvironment
|
||||
// testEnvironmentOptions: {},
|
||||
|
||||
// Adds a location field to test results
|
||||
// testLocationInResults: false,
|
||||
|
||||
// The glob patterns Jest uses to detect test files
|
||||
// testMatch: [
|
||||
// "**/__tests__/**/*.[jt]s?(x)",
|
||||
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
// testPathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||
// testRegex: [],
|
||||
|
||||
// This option allows the use of a custom results processor
|
||||
// testResultsProcessor: undefined,
|
||||
|
||||
// This option allows use of a custom test runner
|
||||
// testRunner: "jasmine2",
|
||||
|
||||
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
|
||||
// testURL: "http://localhost",
|
||||
|
||||
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
|
||||
// timers: "real",
|
||||
|
||||
// A map from regular expressions to paths to transformers
|
||||
// transform: undefined,
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// transformIgnorePatterns: [
|
||||
// "/node_modules/",
|
||||
// "\\.pnp\\.[^\\/]+$"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
// Indicates whether each individual test should be reported during the run
|
||||
// verbose: undefined,
|
||||
|
||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||
// watchPathIgnorePatterns: [],
|
||||
|
||||
// Whether to use watchman for file crawling
|
||||
// watchman: true,
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
module.exports = {
|
||||
async rewrites() {
|
||||
return [
|
||||
// This redirects requests recieved at / the root to the /api/ folder.
|
||||
{
|
||||
source: "/:rest*",
|
||||
destination: "/api/:rest*",
|
||||
},
|
||||
// This redirects requests to api/v*/ to /api/ passing version as a query parameter.
|
||||
{
|
||||
source: "/api/v:version/:rest*",
|
||||
destination: "/api/:rest*?version=:version",
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
16
package.json
16
package.json
|
@ -11,17 +11,27 @@
|
|||
"start": "next start",
|
||||
"build": "next build",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"type-check": "tsc --pretty --noEmit",
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.8",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@calcom/prisma": "*",
|
||||
"@calcom/tsconfig": "*",
|
||||
"scripts": "*",
|
||||
"typescript": "^4.5.3"
|
||||
"babel-jest": "^27.5.1",
|
||||
"install": "^0.13.0",
|
||||
"jest": "^27.5.1",
|
||||
"node-mocks-http": "^1.11.0",
|
||||
"npm": "^8.5.5",
|
||||
"typescript": "^4.5.3",
|
||||
"zod": "^3.14.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@next-auth/prisma-adapter": "^1.0.1",
|
||||
"next": "^12.1.0"
|
||||
"next": "^12.1.0",
|
||||
"next-auth": "^4.3.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function middleware(req: NextApiRequest) {
|
||||
// return early if url isn't supposed to be protected
|
||||
// if (!req.url.includes("/protected-url")) {
|
||||
// return NextResponse.next()
|
||||
// }
|
||||
console.log(req.headers);
|
||||
const session = await getToken({ req, secret: process.env.SECRET });
|
||||
// You could also check for any property on the session object,
|
||||
// like role === "admin" or name === "John Doe", etc.
|
||||
if (!session) {
|
||||
return NextResponse.redirect("https://localhost:3002/unauthorized");
|
||||
}
|
||||
|
||||
// If user is authenticated, continue.
|
||||
return NextResponse.next();
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
import { PrismaAdapter } from "@next-auth/prisma-adapter";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import NextAuth, { NextAuthOptions } from "next-auth";
|
||||
import EmailProvider from "next-auth/providers/email";
|
||||
|
||||
// FIXME: not working when importing prisma directly from our project
|
||||
// import prisma from "@calcom/prisma";
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
adapter: PrismaAdapter(prisma),
|
||||
// https://next-auth.js.org/configuration/providers
|
||||
providers: [
|
||||
EmailProvider({
|
||||
maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only
|
||||
// sendVerificationRequest,
|
||||
}),
|
||||
],
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
session: {
|
||||
// Use JSON Web Tokens for session instead of database sessions.
|
||||
// This option can be used with or without a database for users/accounts.
|
||||
// Note: `strategy` should be set to 'jwt' if no database is used.
|
||||
|
||||
// TODO: Do we want to move 'database' sessions at some point?
|
||||
strategy: "jwt",
|
||||
// Seconds - How long until an idle session expires and is no longer valid.
|
||||
// maxAge: 30 * 24 * 60 * 60, // 30 days
|
||||
|
||||
// Seconds - Throttle how frequently to write to database to extend a session.
|
||||
// Use it to limit write operations. Set to 0 to always update the database.
|
||||
// Note: This option is ignored if using JSON Web Tokens
|
||||
// updateAge: 24 * 60 * 60, // 24 hours
|
||||
},
|
||||
|
||||
// JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session
|
||||
// option is set - or by default if no database is specified.
|
||||
// https://next-auth.js.org/configuration/options#jwt
|
||||
jwt: {
|
||||
// A secret to use for key generation (you should set this explicitly)
|
||||
secret: process.env.SECRET,
|
||||
// Set to true to use encryption (default: false)
|
||||
// encryption: true,
|
||||
// You can define your own encode/decode functions for signing and encryption
|
||||
// if you want to override the default behaviour.
|
||||
// encode: async ({ secret, token, maxAge }) => {},
|
||||
// decode: async ({ secret, token, maxAge }) => {},
|
||||
},
|
||||
// https://next-auth.js.org/configuration/pages
|
||||
// NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com
|
||||
pages: {
|
||||
signIn: "/", // Displays signin buttons
|
||||
signOut: "/", // Displays form with sign out button
|
||||
error: "/", // Error code passed in query string as ?error=
|
||||
verifyRequest: "/", // Used for check email page
|
||||
newUser: "/", // If set, new users will be directed here on first sign in
|
||||
},
|
||||
|
||||
// Callbacks are asynchronous functions you can use to control what happens
|
||||
// when an action is performed.
|
||||
// https://next-auth.js.org/configuration/callbacks
|
||||
|
||||
callbacks: {
|
||||
// async signIn({ user, account, profile, email, credentials }) { return true },
|
||||
// async redirect({ url, baseUrl }) { return baseUrl },
|
||||
// async session({ session, token, user }) { return session },
|
||||
// FIXME: add a custom jwt callback, that is stored outside next-auth
|
||||
// and can be reused to generate valid Personal Access Tokens for the API.
|
||||
// async jwt({ token, user, account, profile, isNewUser }) { return token }
|
||||
},
|
||||
|
||||
// Events are useful for logging
|
||||
// https://next-auth.js.org/configuration/events
|
||||
|
||||
// Enable debug messages in the console if you are having problems
|
||||
debug: false,
|
||||
};
|
||||
export default NextAuth(authOptions);
|
|
@ -0,0 +1,19 @@
|
|||
import { EventType } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
type EventIdData = {
|
||||
event?: EventType;
|
||||
error?: any;
|
||||
};
|
||||
|
||||
export default async function eventType(req: NextApiRequest, res: NextApiResponse<EventIdData>) {
|
||||
try {
|
||||
const event = await prisma.eventType.findUnique({ where: { id: Number(req.query.id) } });
|
||||
res.status(200).json({ event });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(400).json({ error: error });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { PrismaClient, EventType } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
type EventTypeIdData = {
|
||||
events?: EventType[];
|
||||
error?: any;
|
||||
};
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function eventType(req: NextApiRequest, res: NextApiResponse<EventTypeIdData>) {
|
||||
try {
|
||||
const eventTypes = await prisma.eventType.findMany({ where: { id: Number(req.query.eventTypeId) } });
|
||||
res.status(200).json({ events: { ...eventTypes } });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// FIXME: Add zod for validation/error handling
|
||||
res.status(400).json({ error: error });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
import { PrismaClient, EventType } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
interface Body {
|
||||
userId: string;
|
||||
|
||||
newOrganization: {
|
||||
name: string;
|
||||
users: string[];
|
||||
};
|
||||
}
|
||||
type EventsData = {
|
||||
event?: EventType;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export default async function createEventLink(req: NextApiRequest, res: NextApiResponse<EventsData>) {
|
||||
const {
|
||||
body: {
|
||||
title,
|
||||
slug,
|
||||
description,
|
||||
position,
|
||||
locations,
|
||||
hidden,
|
||||
teamId,
|
||||
eventName,
|
||||
timeZone,
|
||||
periodType,
|
||||
periodStartDate,
|
||||
periodEndDate,
|
||||
periodDays,
|
||||
periodCountCalendarDays,
|
||||
requiresConfirmation,
|
||||
disableGuests,
|
||||
minimumBookingNotice,
|
||||
beforeEventBuffer,
|
||||
afterEventBuffer,
|
||||
schedulingType,
|
||||
price,
|
||||
currency,
|
||||
slotInterval,
|
||||
metadata,
|
||||
length,
|
||||
},
|
||||
method,
|
||||
} = req;
|
||||
if (method === "POST") {
|
||||
// Process a POST request
|
||||
const newEvent = await prisma.eventType.create({
|
||||
data: {
|
||||
title: `${title}`,
|
||||
slug: `${slug}`,
|
||||
length: Number(length),
|
||||
// description: description as string,
|
||||
// position: Number(position),
|
||||
// locations: locations,
|
||||
// hidden: Boolean(hidden) as boolean,
|
||||
// teamId: Number.isInteger(teamId) ? Number(teamId) : null,
|
||||
// eventName: eventName,
|
||||
// timeZone: timeZone,
|
||||
// periodType: periodType,
|
||||
// periodStartDate: periodStartDate,
|
||||
// periodEndDate: periodEndDate,
|
||||
// periodDays: periodDays,
|
||||
// periodCountCalendarDays: periodCountCalendarDays,
|
||||
// requiresConfirmation: requiresConfirmation,
|
||||
// disableGuests: disableGuests,
|
||||
// minimumBookingNotice: minimumBookingNotice,
|
||||
// beforeEventBuffer: beforeEventBuffer,
|
||||
// afterEventBuffer: afterEventBuffer,
|
||||
// schedulingType: schedulingType,
|
||||
// price: price,
|
||||
// currency: currency,
|
||||
// slotInterval: slotInterval,
|
||||
// metadata: metadata,
|
||||
},
|
||||
});
|
||||
res.status(201).json({ event: newEvent });
|
||||
} else {
|
||||
// Handle any other HTTP method
|
||||
res.status(405).json({ error: "Only POST Method allowed" });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET;
|
||||
export default async function jwt(req: NextApiRequest, res: NextApiResponse) {
|
||||
const token = await getToken({ req, secret });
|
||||
res.send(JSON.stringify(token, null, 2));
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
// This local import doesn't work
|
||||
// import { PrismaClient } from "@calcom/prisma";
|
||||
const prisma = new PrismaClient();
|
||||
const secret = process.env.NEXTAUTH_SECRET;
|
||||
|
||||
type Data = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export default async function me(req: NextApiRequest, res: NextApiResponse<Data>) {
|
||||
const token = await getToken({ req, secret, raw: false });
|
||||
console.log("token", token);
|
||||
if (!token)
|
||||
return res.status(404).json({
|
||||
message: `You're not authenticated. Provide a valid Session JWT as Authorization: 'Bearer {your_token_here}'`,
|
||||
});
|
||||
if (!token.email)
|
||||
return res.status(404).json({
|
||||
message: `Your token doesn't have a valid email`,
|
||||
});
|
||||
const email: string | undefined = token?.email;
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
email: email,
|
||||
},
|
||||
});
|
||||
return res.json({
|
||||
message: `Hello ${user?.name}, your email is ${user?.email}, and your email is ${
|
||||
user?.emailVerified ? "verified" : "unverified"
|
||||
}`,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// This is an example of how to read a JSON Web Token from an API route
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET;
|
||||
|
||||
export default async function jwt(req: NextApiRequest, res: NextApiResponse) {
|
||||
const token = await getToken({ req, secret, raw: false });
|
||||
if (token) {
|
||||
res.send({
|
||||
content: "This is protected content. You can access this content because you are signed in.",
|
||||
token,
|
||||
});
|
||||
} else {
|
||||
res.send({
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
import { authOptions } from "./auth/[...nextauth]";
|
||||
|
||||
export default async function session(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getServerSession({ req, res }, authOptions);
|
||||
/* ... */
|
||||
if (session) {
|
||||
res.send(JSON.stringify(session, null, 2));
|
||||
} else {
|
||||
res.end();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
// This local import doesn't work
|
||||
// import { PrismaClient } from "@calcom/prisma";
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
type Data = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export default async function userId(req: NextApiRequest, res: NextApiResponse<Data>) {
|
||||
const { id }: { id?: string } = req.query;
|
||||
if (!id) return res.status(404).json({ message: `User not found` });
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: parseInt(id),
|
||||
},
|
||||
});
|
||||
return res.json({ message: `Hello ${user?.name}` });
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET;
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// if using `NEXTAUTH_SECRET` env variable, we detect it, and you won't actually need to `secret`
|
||||
// const token = await getToken({ req })
|
||||
const token = await getToken({ req, secret, raw: true });
|
||||
console.log("JSON Web Token", token);
|
||||
res.end()
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// This is an example of to protect an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const session = await getSession({ req })
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
// This is an example of how to access a session from an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const session = await getSession({ req })
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
}
|
|
@ -1,23 +1,13 @@
|
|||
{
|
||||
"extends": "@calcom/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"ES2015"
|
||||
],
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"resolveJsonModule": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"baseUrl": "./",
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"./pages/api/*.ts"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue