Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5e5ca87ef | ||
|
|
03f860ee6f | ||
|
|
1e3d306eb5 | ||
|
|
0656c94885 | ||
|
|
d1f2e624e9 | ||
|
|
e4d646a643 | ||
|
|
a8a8325176 |
@@ -1,6 +1,5 @@
|
||||
import {Suspense} from "react"
|
||||
import {Head, Link, useSession, useRouterQuery, useMutation, invoke} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import trackView from "app/users/mutations/trackView"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {useCurrentUser} from "app/hooks/useCurrentUser"
|
||||
|
||||
23
examples/auth/app/users/components/UserForm.tsx
Normal file
23
examples/auth/app/users/components/UserForm.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from "react"
|
||||
|
||||
type UserFormProps = {
|
||||
initialValues: any
|
||||
onSubmit: React.FormEventHandler<HTMLFormElement>
|
||||
}
|
||||
|
||||
const UserForm = ({initialValues, onSubmit}: UserFormProps) => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
onSubmit(event)
|
||||
}}
|
||||
>
|
||||
<div>Put your form fields here. But for now, just click submit</div>
|
||||
<div>{JSON.stringify(initialValues)}</div>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserForm
|
||||
16
examples/auth/app/users/mutations/createUser.ts
Normal file
16
examples/auth/app/users/mutations/createUser.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
async function createUser(input, {session}) {
|
||||
const user = await db.user.create({data: input})
|
||||
|
||||
return user
|
||||
},
|
||||
)
|
||||
16
examples/auth/app/users/mutations/deleteUser.ts
Normal file
16
examples/auth/app/users/mutations/deleteUser.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
id: z.number(),
|
||||
}),
|
||||
},
|
||||
async function deleteUser({id}, {session}) {
|
||||
const user = await db.user.delete({where: {id}})
|
||||
|
||||
return user
|
||||
},
|
||||
)
|
||||
17
examples/auth/app/users/mutations/updateUser.ts
Normal file
17
examples/auth/app/users/mutations/updateUser.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
async function updateUser({id, ...data}, {session}) {
|
||||
const user = await db.user.update({where: {id}, data})
|
||||
|
||||
return user
|
||||
},
|
||||
)
|
||||
54
examples/auth/app/users/pages/users/[userId].tsx
Normal file
54
examples/auth/app/users/pages/users/[userId].tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import React, {Suspense} from "react"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {Link, useRouter, useQuery, useParam, BlitzPage} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import deleteUser from "app/users/mutations/deleteUser"
|
||||
|
||||
export const User = () => {
|
||||
const router = useRouter()
|
||||
const userId = useParam("userId", "number")
|
||||
const [user] = useQuery(getUser, {id: userId})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>User {user.id}</h1>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
|
||||
<Link href="/users/[userId]/edit" as={`/users/${user.id}/edit`}>
|
||||
<a>Edit</a>
|
||||
</Link>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
if (window.confirm("This will be deleted")) {
|
||||
await deleteUser({id: user.id})
|
||||
router.push("/users")
|
||||
}
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ShowUserPage: BlitzPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<User />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ShowUserPage.getLayout = (page) => <Layout title={"User"}>{page}</Layout>
|
||||
|
||||
export default ShowUserPage
|
||||
58
examples/auth/app/users/pages/users/[userId]/edit.tsx
Normal file
58
examples/auth/app/users/pages/users/[userId]/edit.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import React, {Suspense} from "react"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {Link, useRouter, useQuery, useMutation, useParam, BlitzPage} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import updateUser from "app/users/mutations/updateUser"
|
||||
import UserForm from "app/users/components/UserForm"
|
||||
|
||||
export const EditUser = () => {
|
||||
const router = useRouter()
|
||||
const userId = useParam("userId", "number")
|
||||
const [user, {mutate}] = useQuery(getUser, {id: userId})
|
||||
const [updateUserMutation] = useMutation(updateUser)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Edit User {user.id}</h1>
|
||||
<pre>{JSON.stringify(user)}</pre>
|
||||
|
||||
<UserForm
|
||||
initialValues={user}
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const updated = await updateUserMutation({
|
||||
id: user.id,
|
||||
name: "MyNewName",
|
||||
})
|
||||
await mutate(updated)
|
||||
alert("Success!" + JSON.stringify(updated))
|
||||
router.push("/users/[userId]", `/users/${updated.id}`)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
alert("Error creating user " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const EditUserPage: BlitzPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<EditUser />
|
||||
</Suspense>
|
||||
|
||||
<p>
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
EditUserPage.getLayout = (page) => <Layout title={"Edit User"}>{page}</Layout>
|
||||
|
||||
export default EditUserPage
|
||||
60
examples/auth/app/users/pages/users/index.tsx
Normal file
60
examples/auth/app/users/pages/users/index.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React, {Suspense} from "react"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {Link, usePaginatedQuery, useRouter, BlitzPage} from "blitz"
|
||||
import getUsers from "app/users/queries/getUsers"
|
||||
|
||||
const ITEMS_PER_PAGE = 100
|
||||
|
||||
export const UsersList = () => {
|
||||
const router = useRouter()
|
||||
const page = Number(router.query.page) || 0
|
||||
const [{users, hasMore}] = usePaginatedQuery(getUsers, {
|
||||
orderBy: {id: "asc"},
|
||||
skip: ITEMS_PER_PAGE * page,
|
||||
take: ITEMS_PER_PAGE,
|
||||
})
|
||||
|
||||
const goToPreviousPage = () => router.push({query: {page: page - 1}})
|
||||
const goToNextPage = () => router.push({query: {page: page + 1}})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<Link href="/users/[userId]" as={`/users/${user.id}`}>
|
||||
<a>{user.name}</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<button disabled={page === 0} onClick={goToPreviousPage}>
|
||||
Previous
|
||||
</button>
|
||||
<button disabled={!hasMore} onClick={goToNextPage}>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const UsersPage: BlitzPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
<Link href="/users/new">
|
||||
<a>Create User</a>
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<UsersList />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
UsersPage.getLayout = (page) => <Layout title={"Users"}>{page}</Layout>
|
||||
|
||||
export default UsersPage
|
||||
39
examples/auth/app/users/pages/users/new.tsx
Normal file
39
examples/auth/app/users/pages/users/new.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from "react"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {Link, useRouter, useMutation, BlitzPage} from "blitz"
|
||||
import createUser from "app/users/mutations/createUser"
|
||||
import UserForm from "app/users/components/UserForm"
|
||||
|
||||
const NewUserPage: BlitzPage = () => {
|
||||
const router = useRouter()
|
||||
const [createUserMutation] = useMutation(createUser)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Create New User</h1>
|
||||
|
||||
<UserForm
|
||||
initialValues={{}}
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const user = await createUserMutation({name: "MyName"})
|
||||
alert("Success!" + JSON.stringify(user))
|
||||
router.push("/users/[userId]", `/users/${user.id}`)
|
||||
} catch (error) {
|
||||
alert("Error creating user " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<p>
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
NewUserPage.getLayout = (page) => <Layout title={"Create New User"}>{page}</Layout>
|
||||
|
||||
export default NewUserPage
|
||||
@@ -1,19 +1,12 @@
|
||||
import {Ctx, NotFoundError} from "blitz"
|
||||
import db, {FindOneUserArgs} from "db"
|
||||
import {protect, NotFoundError} from "blitz"
|
||||
import db, {FindFirstUserArgs} from "db"
|
||||
|
||||
type GetUserInput = {
|
||||
where: FindOneUserArgs["where"]
|
||||
}
|
||||
type GetUserInput = FindFirstUserArgs["where"]
|
||||
|
||||
export default async function getUser({where}: GetUserInput, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
console.log(ctx.session.userId)
|
||||
export default protect({}, async function getUser(input: GetUserInput, {session}) {
|
||||
const user = await db.user.findFirst({where: input})
|
||||
|
||||
const user = await db.user.findOne({where})
|
||||
if (!user) throw new NotFoundError()
|
||||
|
||||
if (!user) throw new NotFoundError(`User with id ${where.id} does not exist`)
|
||||
|
||||
const {hashedPassword, ...rest} = user
|
||||
|
||||
return rest
|
||||
}
|
||||
return user
|
||||
})
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import {Ctx} from "blitz"
|
||||
import {protect} from "blitz"
|
||||
import db, {FindManyUserArgs} from "db"
|
||||
|
||||
type GetUsersInput = {
|
||||
where?: FindManyUserArgs["where"]
|
||||
orderBy?: FindManyUserArgs["orderBy"]
|
||||
cursor?: FindManyUserArgs["cursor"]
|
||||
take?: FindManyUserArgs["take"]
|
||||
skip?: FindManyUserArgs["skip"]
|
||||
}
|
||||
type GetUsersInput = Pick<FindManyUserArgs, "orderBy" | "skip" | "take">
|
||||
|
||||
export default async function getUsers(
|
||||
{where, orderBy, cursor, take, skip}: GetUsersInput,
|
||||
ctx: Ctx,
|
||||
export default protect({}, async function getUsers(
|
||||
{orderBy, skip = 0, take}: GetUsersInput,
|
||||
{session},
|
||||
) {
|
||||
ctx.session.authorize(["admin", "user"])
|
||||
|
||||
const users = await db.user.findMany({
|
||||
where,
|
||||
select: {id: true},
|
||||
where: {
|
||||
// add your selection criteria here
|
||||
},
|
||||
orderBy,
|
||||
cursor,
|
||||
take,
|
||||
skip,
|
||||
})
|
||||
|
||||
return users
|
||||
}
|
||||
const count = await db.user.count()
|
||||
const hasMore = typeof take === "number" ? skip + take < count : false
|
||||
const nextPage = hasMore ? {take, skip: skip + take!} : null
|
||||
|
||||
return {
|
||||
users,
|
||||
nextPage,
|
||||
hasMore,
|
||||
count,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -43,3 +43,27 @@ model Session {
|
||||
publicData String?
|
||||
privateData String?
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @default(autoincrement()) @id
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @default(autoincrement()) @id
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @default(autoincrement()) @id
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @default(autoincrement()) @id
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"prisma": {
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100,
|
||||
@@ -33,8 +36,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"@prisma/cli": "2.8.0",
|
||||
"@prisma/client": "2.8.0",
|
||||
"blitz": "0.24.0-canary.0",
|
||||
"final-form": "4.20.1",
|
||||
"passport-auth0": "1.3.3",
|
||||
@@ -45,7 +48,7 @@
|
||||
"react-error-boundary": "2.3.1",
|
||||
"react-final-form": "6.5.1",
|
||||
"secure-password": "4.0.0",
|
||||
"zod": "1.10.0"
|
||||
"zod": "1.11.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/skip-test": "2.5.0",
|
||||
|
||||
@@ -134,7 +134,8 @@
|
||||
"tsdx": "0.13.3",
|
||||
"tslib": "1.11.1",
|
||||
"typescript": "4.0.3",
|
||||
"wait-on": "4.0.2"
|
||||
"wait-on": "4.0.2",
|
||||
"zod": "1.11.9"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
||||
28
packages/core/src/authorization.ts
Normal file
28
packages/core/src/authorization.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {Ctx} from "./middleware"
|
||||
import {AuthenticatedSessionContext} from "./supertokens"
|
||||
import {ZodSchema, infer as zInfer} from "zod"
|
||||
|
||||
export type ProtectArgs<T> = {schema?: T; authorize?: boolean | unknown}
|
||||
|
||||
interface AuthenticatedCtx extends Ctx {
|
||||
session: AuthenticatedSessionContext
|
||||
}
|
||||
|
||||
export const protect = <T extends ZodSchema<any, any>, U = zInfer<T>>(
|
||||
{schema, authorize = true}: ProtectArgs<T>,
|
||||
resolver: (args: U, ctx: AuthenticatedCtx) => any,
|
||||
) => {
|
||||
return (rawInput: U, ctx: Ctx) => {
|
||||
if (authorize) {
|
||||
const authorizeInput: any[] = ["superadmin", "SUPERADMIN"]
|
||||
if (Array.isArray(authorize)) {
|
||||
authorizeInput.push(...authorize)
|
||||
} else if (typeof authorize !== "boolean") {
|
||||
authorizeInput.push(authorize)
|
||||
}
|
||||
;(ctx as any).session.authorize(authorizeInput)
|
||||
}
|
||||
const input = schema ? schema.parse(rawInput) : rawInput
|
||||
return resolver(input, ctx as AuthenticatedCtx)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export * from "./use-query-hooks"
|
||||
export {useMutation} from "./use-mutation"
|
||||
export {invoke, invokeWithMiddleware} from "./invoke"
|
||||
export {getQueryKey, invalidateQuery} from "./utils/react-query-utils"
|
||||
export {protect} from "./authorization"
|
||||
export * from "./use-params"
|
||||
export * from "./rpc"
|
||||
export * from "./with-router"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Ctx } from "blitz"
|
||||
import { protect } from "blitz"
|
||||
import { authenticateUser } from "app/auth/auth-utils"
|
||||
import { LoginInput, LoginInputType } from "../validations"
|
||||
|
||||
export default async function login(input: LoginInputType, { session }: Ctx) {
|
||||
// This throws an error if input is invalid
|
||||
const { email, password } = LoginInput.parse(input)
|
||||
import { LoginInput } from "../validations"
|
||||
|
||||
export default protect({ schema: LoginInput, authorize: false }, async function login(
|
||||
{ email, password },
|
||||
{ session }
|
||||
) {
|
||||
// This throws an error if credentials are invalid
|
||||
const user = await authenticateUser(email, password)
|
||||
|
||||
await session.create({ userId: user.id, roles: [user.role] })
|
||||
|
||||
return user
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Ctx } from "blitz"
|
||||
import { protect } from "blitz"
|
||||
import db from "db"
|
||||
import { hashPassword } from "app/auth/auth-utils"
|
||||
import { SignupInput, SignupInputType } from "app/auth/validations"
|
||||
|
||||
export default async function signup(input: SignupInputType, { session }: Ctx) {
|
||||
// This throws an error if input is invalid
|
||||
const { email, password } = SignupInput.parse(input)
|
||||
import { SignupInput } from "app/auth/validations"
|
||||
|
||||
export default protect({ schema: SignupInput, authorize: false }, async function signup(
|
||||
{ email, password },
|
||||
{ session }
|
||||
) {
|
||||
const hashedPassword = await hashPassword(password)
|
||||
const user = await db.user.create({
|
||||
data: { email: email.toLowerCase(), hashedPassword, role: "user" },
|
||||
@@ -16,4 +16,4 @@ export default async function signup(input: SignupInputType, { session }: Ctx) {
|
||||
await session.create({ userId: user.id, roles: [user.role] })
|
||||
|
||||
return user
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4,10 +4,8 @@ export const SignupInput = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(10).max(100),
|
||||
})
|
||||
export type SignupInputType = z.infer<typeof SignupInput>
|
||||
|
||||
export const LoginInput = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string(),
|
||||
})
|
||||
export type LoginInputType = z.infer<typeof LoginInput>
|
||||
|
||||
@@ -19,7 +19,7 @@ model User {
|
||||
name String?
|
||||
email String @unique
|
||||
hashedPassword String?
|
||||
role String @default("user")
|
||||
role String
|
||||
sessions Session[]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db, {__ModelName__CreateArgs} from "db"
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
if (process.env.parentModel) {
|
||||
type Create__ModelName__Input = {
|
||||
data: Omit<__ModelName__CreateArgs["data"], "__parentModel__">
|
||||
__parentModelId__: number
|
||||
}
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
__parentModelId__: z.number(),
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
async function create__ModelName__({__parentModelId__, ...input}, {session}) {
|
||||
const __modelName__ = await db.__modelName__.create({
|
||||
data: {...input, __parentModel__: {connect: {id: __parentModelId__}}},
|
||||
})
|
||||
|
||||
return __modelName__
|
||||
},
|
||||
)
|
||||
} else {
|
||||
type Create__ModelName__Input = Pick<__ModelName__CreateArgs, "data">
|
||||
}
|
||||
|
||||
if (process.env.parentModel) {
|
||||
export default async function create__ModelName__(
|
||||
{data, __parentModelId__}: Create__ModelName__Input,
|
||||
ctx: Ctx,
|
||||
) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const __modelName__ = await db.__modelName__.create({
|
||||
data: {...data, __parentModel__: {connect: {id: __parentModelId__}}},
|
||||
})
|
||||
|
||||
return __modelName__
|
||||
}
|
||||
} else {
|
||||
export default async function create__ModelName__({data}: Create__ModelName__Input, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const __modelName__ = await db.__modelName__.create({data})
|
||||
|
||||
return __modelName__
|
||||
}
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
async function create__ModelName__(input, {session}) {
|
||||
const __modelName__ = await db.__modelName__.create({data: input})
|
||||
|
||||
return __modelName__
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db, {__ModelName__DeleteArgs} from "db"
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
type Delete__ModelName__Input = Pick<__ModelName__DeleteArgs, "where">
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
id: z.number(),
|
||||
}),
|
||||
},
|
||||
async function delete__ModelName__({id}, {session}) {
|
||||
const __modelName__ = await db.__modelName__.delete({where: {id}})
|
||||
|
||||
export default async function delete__ModelName__({where}: Delete__ModelName__Input, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const __modelName__ = await db.__modelName__.delete({where})
|
||||
|
||||
return __modelName__
|
||||
}
|
||||
return __modelName__
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db, {__ModelName__UpdateArgs} from "db"
|
||||
import {protect} from "blitz"
|
||||
import db from "db"
|
||||
import * as z from "zod"
|
||||
|
||||
if (process.env.parentModel) {
|
||||
type Update__ModelName__Input = {
|
||||
where: __ModelName__UpdateArgs["where"]
|
||||
data: Omit<__ModelName__UpdateArgs["data"], "__parentModel__">
|
||||
__parentModelId__: number
|
||||
}
|
||||
} else {
|
||||
type Update__ModelName__Input = Pick<__ModelName__UpdateArgs, "where" | "data">
|
||||
}
|
||||
export default protect(
|
||||
{
|
||||
schema: z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
}),
|
||||
},
|
||||
async function update__ModelName__({id, ...data}, {session}) {
|
||||
const __modelName__ = await db.__modelName__.update({where: {id}, data})
|
||||
|
||||
export default async function update__ModelName__(
|
||||
{where, data}: Update__ModelName__Input,
|
||||
ctx: Ctx,
|
||||
) {
|
||||
ctx.session.authorize()
|
||||
|
||||
if (process.env.parentModel) {
|
||||
// Don't allow updating
|
||||
delete (data as any).__parentModel__
|
||||
}
|
||||
|
||||
const __modelName__ = await db.__modelName__.update({where, data})
|
||||
|
||||
return __modelName__
|
||||
}
|
||||
return __modelName__
|
||||
},
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ export const __ModelName__ = () => {
|
||||
if (process.env.parentModel) {
|
||||
const __parentModelId__ = useParam("__parentModelId__", "number")
|
||||
}
|
||||
const [__modelName__] = useQuery(get__ModelName__, {where: {id: __modelId__}})
|
||||
const [__modelName__] = useQuery(get__ModelName__, {id: __modelId__})
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +38,7 @@ export const __ModelName__ = () => {
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
if (window.confirm("This will be deleted")) {
|
||||
await delete__ModelName__({where: {id: __modelName__.id}})
|
||||
await delete__ModelName__({id: __modelName__.id})
|
||||
if (process.env.parentModel) {
|
||||
router.push(
|
||||
"/__parentModels__/__parentModelParam__/__modelNames__",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const Edit__ModelName__ = () => {
|
||||
if (process.env.parentModel) {
|
||||
const __parentModelId__ = useParam("__parentModelId__", "number")
|
||||
}
|
||||
const [__modelName__, {mutate}] = useQuery(get__ModelName__, {where: {id: __modelId__}})
|
||||
const [__modelName__, {mutate}] = useQuery(get__ModelName__, {id: __modelId__})
|
||||
const [update__ModelName__Mutation] = useMutation(update__ModelName__)
|
||||
|
||||
return (
|
||||
@@ -24,8 +24,8 @@ export const Edit__ModelName__ = () => {
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const updated = await update__ModelName__Mutation({
|
||||
where: {id: __modelName__.id},
|
||||
data: {name: "MyNewName"},
|
||||
id: __modelName__.id,
|
||||
name: "MyNewName",
|
||||
})
|
||||
await mutate(updated)
|
||||
alert("Success!" + JSON.stringify(updated))
|
||||
|
||||
@@ -24,9 +24,7 @@ const New__ModelName__Page: BlitzPage = () => {
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const __modelName__ = await create__ModelName__Mutation(
|
||||
process.env.parentModel
|
||||
? {data: {name: "MyName"}, __parentModelId__}
|
||||
: {data: {name: "MyName"}},
|
||||
process.env.parentModel ? {name: "MyName", __parentModelId__} : {name: "MyName"},
|
||||
)
|
||||
alert("Success!" + JSON.stringify(__modelName__))
|
||||
router.push(
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import {Ctx, NotFoundError} from "blitz"
|
||||
import {protect, NotFoundError} from "blitz"
|
||||
import db, {FindFirst__ModelName__Args} from "db"
|
||||
|
||||
type Get__ModelName__Input = Pick<FindFirst__ModelName__Args, "where">
|
||||
type Get__ModelName__Input = FindFirst__ModelName__Args["where"]
|
||||
|
||||
export default async function get__ModelName__({where}: Get__ModelName__Input, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const __modelName__ = await db.__modelName__.findFirst({where})
|
||||
export default protect({}, async function get__ModelName__(
|
||||
input: Get__ModelName__Input,
|
||||
{session},
|
||||
) {
|
||||
const __modelName__ = await db.__modelName__.findFirst({where: input})
|
||||
|
||||
if (!__modelName__) throw new NotFoundError()
|
||||
|
||||
return __modelName__
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import {Ctx} from "blitz"
|
||||
import {protect} from "blitz"
|
||||
import db, {FindMany__ModelName__Args} from "db"
|
||||
|
||||
type Get__ModelNames__Input = Pick<FindMany__ModelName__Args, "where" | "orderBy" | "skip" | "take">
|
||||
type Get__ModelNames__Input = Pick<FindMany__ModelName__Args, "orderBy" | "skip" | "take">
|
||||
|
||||
export default async function get__ModelNames__(
|
||||
{where, orderBy, skip = 0, take}: Get__ModelNames__Input,
|
||||
ctx: Ctx,
|
||||
export default protect({}, async function get__ModelNames__(
|
||||
{orderBy, skip = 0, take}: Get__ModelNames__Input,
|
||||
{session},
|
||||
) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const __modelNames__ = await db.__modelName__.findMany({
|
||||
where,
|
||||
where: {
|
||||
// add your selection criteria here
|
||||
},
|
||||
orderBy,
|
||||
take,
|
||||
skip,
|
||||
@@ -26,4 +26,4 @@ export default async function get__ModelNames__(
|
||||
hasMore,
|
||||
count,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import {Ctx} from "blitz"
|
||||
import {protect, NotFoundError} from "blitz"
|
||||
import db from "db"
|
||||
|
||||
export default async function __rawInput__(input, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
|
||||
export default protect({}, async function __rawInput__(input, {session}) {
|
||||
// Do your stuff :)
|
||||
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
20
yarn.lock
20
yarn.lock
@@ -3475,6 +3475,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@prisma/cli/-/cli-2.4.1.tgz#95f6cae48ff19c6177bb9f85816b27e1ffe5af53"
|
||||
integrity sha512-vAOBnouBgCYndXmTcGxanfmhVWUCpwr3akBXiQH+ZKzTYf/pwSsWYpeaXNQfVtUEJEQ0kumfLGdq6ZXnfX//aA==
|
||||
|
||||
"@prisma/cli@2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/cli/-/cli-2.8.0.tgz#919d7f66023affa76d14823212b62a8512cfd37d"
|
||||
integrity sha512-Kg1C47d75jdEIMmJif8TMlv/2Ihx08E1qWp0euwoZhjd807HGnjgC9tJYjTfkdf+NMJSAUbvoPXKInEX0HoOMw==
|
||||
|
||||
"@prisma/client@2.4.1":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.4.1.tgz#840d0905e9d05d84313e333a3e0370df3b9815fe"
|
||||
@@ -3482,6 +3487,13 @@
|
||||
dependencies:
|
||||
pkg-up "^3.1.0"
|
||||
|
||||
"@prisma/client@2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.8.0.tgz#a0f7247786c9b6ee804437acf8215854c5eb3946"
|
||||
integrity sha512-5+GzRTkPnmv4OEV2tB8kwQt/xLLxBR/daJBcMt6pnnonJvrREsu0tSTdz2LJNPaj3kTT0fSS/OaeGMMdfVYSpw==
|
||||
dependencies:
|
||||
pkg-up "^3.1.0"
|
||||
|
||||
"@prisma/debug@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-2.6.0.tgz#7623862e310f7b30d64481643f693742ce562ee0"
|
||||
@@ -19852,7 +19864,7 @@ zip-stream@^3.0.1:
|
||||
compress-commons "^3.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
zod@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-1.10.0.tgz#175286f09d480ac604014245d7215f67959b0d7a"
|
||||
integrity sha512-u06UhgHEUzLN26qDI7Ei9sqWdiQjQnrjEJtAXmAHF3fH35sOkPmdAl4FNZOgsigv2Jki6yrx5wivQyYXB4B+aA==
|
||||
zod@1.11.9:
|
||||
version "1.11.9"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-1.11.9.tgz#c6c503804d394f8ef009d44ce464bbf8aa3c1bd6"
|
||||
integrity sha512-qZjs9DkvPYHOiOUdAtNcxOC0u5cv7tx9DCmlNZN0MxWeFvgqyr3XkXFqUlaSpmTiZ4A4YVkB2s1Zw2ENJ9/fSg==
|
||||
|
||||
Reference in New Issue
Block a user