Added user query, some code refactors
This commit is contained in:
parent
ec2c5feb69
commit
301281b7fc
@ -9,15 +9,17 @@ import jwt from 'jsonwebtoken'
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
|
||||||
import { getDBFormAuthor } from '../db'
|
import { getDBFormAuthor } from '../db'
|
||||||
|
import { sendToken } from '../mailer'
|
||||||
import { CheckRightsAndResolve } from './types'
|
import { CheckRightsAndResolve } from './types'
|
||||||
|
|
||||||
const checkRightsAndResolve: CheckRightsAndResolve = async (params) => {
|
const checkRightsAndResolve: CheckRightsAndResolve = async (params) => {
|
||||||
const { user, expected, controller } = params
|
const { user, expected, controller } = params
|
||||||
|
|
||||||
if (!user) throw new AuthenticationError('Authentication required')
|
if (!user) throw new AuthenticationError('Authorization required')
|
||||||
|
|
||||||
if (expected.id.self) return controller(user.id)
|
if (expected.id && expected.self) return controller(expected.id || user.id)
|
||||||
if (!expected.id.n || user.id == expected.id.n) return controller()
|
if (expected.self) return controller(user.id)
|
||||||
|
if (!expected.id || user.id == expected.id) return controller()
|
||||||
|
|
||||||
throw new ForbiddenError('Access denied')
|
throw new ForbiddenError('Access denied')
|
||||||
}
|
}
|
||||||
@ -39,4 +41,15 @@ const tokenGenerate = (email: string, id: number) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { checkRightsAndResolve, getFormAuthor, tokenGenerate }
|
const sendTokenEmail = async (
|
||||||
|
email: string,
|
||||||
|
user: { id: number; name: string }
|
||||||
|
) => {
|
||||||
|
const token = tokenGenerate(email, user.id)
|
||||||
|
|
||||||
|
const res = await sendToken(user.name, email, token)
|
||||||
|
|
||||||
|
if (res[0].statusCode != 202) return new ApolloError("Couldn't send email")
|
||||||
|
}
|
||||||
|
|
||||||
|
export { checkRightsAndResolve, getFormAuthor, tokenGenerate, sendTokenEmail }
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import { JwtPayloadType } from "../types"
|
import { JwtPayloadType } from '../types'
|
||||||
|
|
||||||
type expectedType = {
|
type expectedType = {
|
||||||
id: {
|
id: number
|
||||||
n: number
|
self: boolean
|
||||||
self: boolean
|
|
||||||
}
|
|
||||||
admin: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICheckRightsAndResolve<T> {
|
interface ICheckRightsAndResolve<T> {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
import { UserInputError } from 'apollo-server-express'
|
||||||
|
import { MutationRegisterArgs } from '../typeDefs/typeDefs.gen'
|
||||||
|
import { IFindUserParams } from './types'
|
||||||
|
|
||||||
const getDBForm = async (db: PrismaClient, id: number) => {
|
const getDBForm = async (db: PrismaClient, id: number) => {
|
||||||
return await db.form.findOne({
|
return await db.form.findOne({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
author: {
|
author: {
|
||||||
@ -11,20 +14,20 @@ const getDBForm = async (db: PrismaClient, id: number) => {
|
|||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
email: true
|
email: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
choisesQuestions: {
|
choisesQuestions: {
|
||||||
include: {
|
include: {
|
||||||
variants: true,
|
variants: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
inputQuestions: true,
|
inputQuestions: true,
|
||||||
submissions: {
|
submissions: {
|
||||||
include: {
|
include: {
|
||||||
answers: true,
|
answers: true
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,38 +35,58 @@ const getDBFormByUser = async (db: PrismaClient, id: number) => {
|
|||||||
return await db.form.findMany({
|
return await db.form.findMany({
|
||||||
where: {
|
where: {
|
||||||
author: {
|
author: {
|
||||||
id,
|
id
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
choisesQuestions: {
|
choisesQuestions: {
|
||||||
include: {
|
include: {
|
||||||
variants: true,
|
variants: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
inputQuestions: true,
|
inputQuestions: true,
|
||||||
submissions: {
|
submissions: {
|
||||||
include: {
|
include: {
|
||||||
answers: true,
|
answers: true
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDBFormAuthor = async (db: PrismaClient, id: number) => {
|
const getDBFormAuthor = async (db: PrismaClient, id: number) => {
|
||||||
return await db.form.findOne({
|
return await db.form.findOne({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
author: {
|
author: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getDBForm, getDBFormByUser, getDBFormAuthor }
|
const createUser = async (
|
||||||
|
db: PrismaClient,
|
||||||
|
{ email, name }: MutationRegisterArgs
|
||||||
|
) => {
|
||||||
|
return await db.user.create({
|
||||||
|
data: { email, name }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const findUserBy = async (db: PrismaClient, params: IFindUserParams) => {
|
||||||
|
const user = await db.user.findOne({
|
||||||
|
where: {
|
||||||
|
...params
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!user) throw new UserInputError('Not found')
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getDBForm, getDBFormByUser, getDBFormAuthor, createUser, findUserBy }
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import { PromiseReturnType } from "@prisma/client"
|
import { PromiseReturnType } from '@prisma/client'
|
||||||
import { getDBForm } from "../db"
|
import { getDBForm } from '../db'
|
||||||
|
|
||||||
type FullForm = PromiseReturnType<typeof getDBForm>
|
type FullForm = PromiseReturnType<typeof getDBForm>
|
||||||
|
|
||||||
export { FullForm }
|
interface IFindUserParams {
|
||||||
|
email?: string
|
||||||
|
id?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FullForm, IFindUserParams }
|
||||||
|
28
src/index.ts
28
src/index.ts
@ -1,31 +1,31 @@
|
|||||||
import { ApolloServer, makeExecutableSchema } from "apollo-server-express"
|
import { ApolloServer, makeExecutableSchema } from 'apollo-server-express'
|
||||||
import express from "express"
|
import express from 'express'
|
||||||
import expressJwt from "express-jwt"
|
import expressJwt from 'express-jwt'
|
||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
require("dotenv").config()
|
require('dotenv').config()
|
||||||
|
|
||||||
import typeDefs from "./typeDefs"
|
import typeDefs from './typeDefs'
|
||||||
import resolvers from "./resolvers"
|
import resolvers from './resolvers'
|
||||||
import { ApolloContextType, JwtPayloadType } from "./types"
|
import { ApolloContextType, JwtPayloadType } from './types'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
expressJwt({
|
expressJwt({
|
||||||
secret: "" + process.env.JWT_SECRET,
|
secret: '' + process.env.JWT_SECRET,
|
||||||
credentialsRequired: false,
|
credentialsRequired: false,
|
||||||
algorithms: ["HS256"],
|
algorithms: ['HS256']
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
const server = new ApolloServer({
|
const server = new ApolloServer({
|
||||||
schema: makeExecutableSchema({
|
schema: makeExecutableSchema({
|
||||||
typeDefs,
|
typeDefs,
|
||||||
resolvers,
|
resolvers
|
||||||
}),
|
}),
|
||||||
context: async ({
|
context: async ({
|
||||||
req,
|
req
|
||||||
}: {
|
}: {
|
||||||
req: Request & { user: JwtPayloadType }
|
req: Request & { user: JwtPayloadType }
|
||||||
}): Promise<ApolloContextType> => {
|
}): Promise<ApolloContextType> => {
|
||||||
@ -34,11 +34,11 @@ const server = new ApolloServer({
|
|||||||
|
|
||||||
return { db, user }
|
return { db, user }
|
||||||
},
|
},
|
||||||
debug: false,
|
debug: false
|
||||||
})
|
})
|
||||||
|
|
||||||
server.applyMiddleware({ app })
|
server.applyMiddleware({ app })
|
||||||
|
|
||||||
app.listen(4000, () => {
|
app.listen(4000, () => {
|
||||||
console.log("Server ready at http://localhost:4000")
|
console.log('Server ready at http://localhost:4000')
|
||||||
})
|
})
|
||||||
|
@ -2,16 +2,16 @@ import {
|
|||||||
checkRightsAndResolve,
|
checkRightsAndResolve,
|
||||||
getForm,
|
getForm,
|
||||||
getFormAuthor,
|
getFormAuthor,
|
||||||
getForms,
|
getForms
|
||||||
} from "../controllers"
|
} from '../controllers'
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
QueryFormArgs,
|
QueryFormArgs,
|
||||||
QuestionResolvers,
|
QuestionResolvers,
|
||||||
Resolver,
|
Resolver,
|
||||||
AnswerResolvers,
|
AnswerResolvers
|
||||||
} from "../typeDefs/typeDefs.gen"
|
} from '../typeDefs/typeDefs.gen'
|
||||||
import { ApolloContextType } from "../types"
|
import { ApolloContextType } from '../types'
|
||||||
|
|
||||||
const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
|
const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
|
||||||
_,
|
_,
|
||||||
@ -26,13 +26,10 @@ const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
|
|||||||
return await checkRightsAndResolve({
|
return await checkRightsAndResolve({
|
||||||
user,
|
user,
|
||||||
expected: {
|
expected: {
|
||||||
id: {
|
id: 0,
|
||||||
n: 0,
|
self: false
|
||||||
self: false,
|
|
||||||
},
|
|
||||||
admin: false,
|
|
||||||
},
|
},
|
||||||
controller: getFormById,
|
controller: getFormById
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return err
|
return err
|
||||||
@ -53,13 +50,10 @@ const formsQuery: Resolver<Form[], {}, ApolloContextType> = async (
|
|||||||
>({
|
>({
|
||||||
user,
|
user,
|
||||||
expected: {
|
expected: {
|
||||||
id: {
|
id: 0,
|
||||||
n: 0,
|
self: true
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
admin: false,
|
|
||||||
},
|
},
|
||||||
controller: getFormsByUserId,
|
controller: getFormsByUserId
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return err
|
return err
|
||||||
@ -69,19 +63,19 @@ const formsQuery: Resolver<Form[], {}, ApolloContextType> = async (
|
|||||||
const QuestionResolver: QuestionResolvers = {
|
const QuestionResolver: QuestionResolvers = {
|
||||||
__resolveType(obj: any) {
|
__resolveType(obj: any) {
|
||||||
if (obj.type) {
|
if (obj.type) {
|
||||||
return "ChoisesQuestion"
|
return 'ChoisesQuestion'
|
||||||
}
|
}
|
||||||
return "InputQuestion"
|
return 'InputQuestion'
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnswerResolver: AnswerResolvers = {
|
const AnswerResolver: AnswerResolvers = {
|
||||||
__resolveType(obj) {
|
__resolveType(obj) {
|
||||||
if (obj.type == "CHOISE") return "ChoiseAnswer"
|
if (obj.type == 'CHOISE') return 'ChoiseAnswer'
|
||||||
if (obj.type == "INPUT") return "InputAnswer"
|
if (obj.type == 'INPUT') return 'InputAnswer'
|
||||||
|
|
||||||
return null
|
return null
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { formQuery, formsQuery, QuestionResolver, AnswerResolver }
|
export { formQuery, formsQuery, QuestionResolver, AnswerResolver }
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { ApolloError, UserInputError } from 'apollo-server-express'
|
import { UserInputError } from 'apollo-server-express'
|
||||||
|
|
||||||
import { tokenGenerate } from '../controllers/auth'
|
import { checkRightsAndResolve, sendTokenEmail } from '../controllers/auth'
|
||||||
import { sendToken } from '../mailer'
|
import { createUser, findUserBy } from '../db'
|
||||||
import {
|
import {
|
||||||
MutationLoginArgs,
|
MutationLoginArgs,
|
||||||
MutationRegisterArgs,
|
MutationRegisterArgs,
|
||||||
Resolver,
|
Resolver,
|
||||||
|
LoginResult,
|
||||||
User,
|
User,
|
||||||
LoginResult
|
QueryUserArgs
|
||||||
} from '../typeDefs/typeDefs.gen'
|
} from '../typeDefs/typeDefs.gen'
|
||||||
import { ApolloContextType } from '../types'
|
import { ApolloContextType } from '../types'
|
||||||
|
|
||||||
@ -18,19 +19,11 @@ const loginResolver: Resolver<
|
|||||||
MutationLoginArgs
|
MutationLoginArgs
|
||||||
> = async (_, { email }, { db }) => {
|
> = async (_, { email }, { db }) => {
|
||||||
try {
|
try {
|
||||||
const user = await db.user.findOne({
|
const user = await findUserBy(db, { email })
|
||||||
where: {
|
|
||||||
email
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!user) throw new UserInputError('No such user')
|
if (!user) throw new UserInputError('No such user')
|
||||||
|
|
||||||
const token = tokenGenerate(email, user.id)
|
await sendTokenEmail(email, user)
|
||||||
|
|
||||||
const res = await sendToken(user.name, email, token)
|
|
||||||
|
|
||||||
if (res[0].statusCode != 202) return new ApolloError("Couldn't send email")
|
|
||||||
|
|
||||||
return { success: true }
|
return { success: true }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -45,15 +38,9 @@ const registerResolver: Resolver<
|
|||||||
MutationRegisterArgs
|
MutationRegisterArgs
|
||||||
> = async (_, { email, name }, { db }) => {
|
> = async (_, { email, name }, { db }) => {
|
||||||
try {
|
try {
|
||||||
const user = await db.user.create({
|
const user = await createUser(db, { email, name })
|
||||||
data: { email, name }
|
|
||||||
})
|
|
||||||
|
|
||||||
const token = tokenGenerate(email, user.id)
|
await sendTokenEmail(email, user)
|
||||||
|
|
||||||
const res = await sendToken(user.name, email, token)
|
|
||||||
|
|
||||||
if (res[0].statusCode != 202) return new ApolloError("Couldn't send email")
|
|
||||||
|
|
||||||
return { success: true }
|
return { success: true }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -61,4 +48,23 @@ const registerResolver: Resolver<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { loginResolver, registerResolver }
|
const userResolver: Resolver<
|
||||||
|
User,
|
||||||
|
{},
|
||||||
|
ApolloContextType,
|
||||||
|
QueryUserArgs
|
||||||
|
> = async (_, { id }, { db, user }) => {
|
||||||
|
const findUserById = (id: number) => findUserBy(db, { id })
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await checkRightsAndResolve({
|
||||||
|
user,
|
||||||
|
expected: { id: id || 0, self: true },
|
||||||
|
controller: findUserById
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { loginResolver, registerResolver, userResolver }
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
import { ApolloContextType } from "../types"
|
import { ApolloContextType } from '../types'
|
||||||
import { Resolvers } from "../typeDefs/typeDefs.gen"
|
import { Resolvers } from '../typeDefs/typeDefs.gen'
|
||||||
import {
|
import {
|
||||||
formQuery as form,
|
formQuery as form,
|
||||||
QuestionResolver as Question,
|
QuestionResolver as Question,
|
||||||
AnswerResolver as Answer,
|
AnswerResolver as Answer,
|
||||||
formsQuery as forms,
|
formsQuery as forms
|
||||||
} from "./Form"
|
} from './Form'
|
||||||
import { loginResolver as login, registerResolver as register } from "./User"
|
import {
|
||||||
|
loginResolver as login,
|
||||||
|
registerResolver as register,
|
||||||
|
userResolver as user
|
||||||
|
} from './User'
|
||||||
|
|
||||||
const resolvers: Resolvers<ApolloContextType> = {
|
const resolvers: Resolvers<ApolloContextType> = {
|
||||||
Query: {
|
Query: {
|
||||||
form,
|
form,
|
||||||
forms,
|
forms,
|
||||||
|
user
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
login,
|
login,
|
||||||
register
|
register
|
||||||
},
|
},
|
||||||
Question,
|
Question,
|
||||||
Answer,
|
Answer
|
||||||
}
|
}
|
||||||
|
|
||||||
export default resolvers
|
export default resolvers
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
type Query {
|
type Query {
|
||||||
forms: [Form!]!
|
forms: [Form!]!
|
||||||
form(id: Int!): Form
|
form(id: Int!): Form
|
||||||
|
user(id: Int): User
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
@ -77,7 +78,6 @@ type User {
|
|||||||
email: String!
|
email: String!
|
||||||
id: Int!
|
id: Int!
|
||||||
forms: [Form!]
|
forms: [Form!]
|
||||||
token: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginResult {
|
type LoginResult {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from '@prisma/client'
|
||||||
import {} from "express-jwt"
|
|
||||||
|
|
||||||
export type ApolloContextType = {
|
export type ApolloContextType = {
|
||||||
db: PrismaClient
|
db: PrismaClient
|
||||||
|
Loading…
x
Reference in New Issue
Block a user