Added user query, some code refactors

This commit is contained in:
Dmitriy Shishkov 2020-10-10 00:19:07 +05:00
parent ec2c5feb69
commit 301281b7fc
10 changed files with 147 additions and 105 deletions

View File

@ -9,15 +9,17 @@ import jwt from 'jsonwebtoken'
require('dotenv').config()
import { getDBFormAuthor } from '../db'
import { sendToken } from '../mailer'
import { CheckRightsAndResolve } from './types'
const checkRightsAndResolve: CheckRightsAndResolve = async (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.n || user.id == expected.id.n) return controller()
if (expected.id && expected.self) return controller(expected.id || user.id)
if (expected.self) return controller(user.id)
if (!expected.id || user.id == expected.id) return controller()
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 }

View File

@ -1,11 +1,8 @@
import { JwtPayloadType } from "../types"
import { JwtPayloadType } from '../types'
type expectedType = {
id: {
n: number
self: boolean
}
admin: boolean
id: number
self: boolean
}
interface ICheckRightsAndResolve<T> {

View File

@ -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) => {
return await db.form.findOne({
where: {
id,
id
},
include: {
author: {
@ -11,20 +14,20 @@ const getDBForm = async (db: PrismaClient, id: number) => {
id: true,
name: true,
email: true
},
}
},
choisesQuestions: {
include: {
variants: true,
},
variants: true
}
},
inputQuestions: true,
submissions: {
include: {
answers: true,
},
},
},
answers: true
}
}
}
})
}
@ -32,38 +35,58 @@ const getDBFormByUser = async (db: PrismaClient, id: number) => {
return await db.form.findMany({
where: {
author: {
id,
},
id
}
},
include: {
choisesQuestions: {
include: {
variants: true,
},
variants: true
}
},
inputQuestions: true,
submissions: {
include: {
answers: true,
},
},
},
answers: true
}
}
}
})
}
const getDBFormAuthor = async (db: PrismaClient, id: number) => {
return await db.form.findOne({
where: {
id,
id
},
select: {
author: {
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 }

View File

@ -1,6 +1,11 @@
import { PromiseReturnType } from "@prisma/client"
import { getDBForm } from "../db"
import { PromiseReturnType } from '@prisma/client'
import { getDBForm } from '../db'
type FullForm = PromiseReturnType<typeof getDBForm>
export { FullForm }
interface IFindUserParams {
email?: string
id?: number
}
export { FullForm, IFindUserParams }

View File

@ -1,31 +1,31 @@
import { ApolloServer, makeExecutableSchema } from "apollo-server-express"
import express from "express"
import expressJwt from "express-jwt"
import { PrismaClient } from "@prisma/client"
import { ApolloServer, makeExecutableSchema } from 'apollo-server-express'
import express from 'express'
import expressJwt from 'express-jwt'
import { PrismaClient } from '@prisma/client'
require("dotenv").config()
require('dotenv').config()
import typeDefs from "./typeDefs"
import resolvers from "./resolvers"
import { ApolloContextType, JwtPayloadType } from "./types"
import typeDefs from './typeDefs'
import resolvers from './resolvers'
import { ApolloContextType, JwtPayloadType } from './types'
const app = express()
app.use(
expressJwt({
secret: "" + process.env.JWT_SECRET,
secret: '' + process.env.JWT_SECRET,
credentialsRequired: false,
algorithms: ["HS256"],
algorithms: ['HS256']
})
)
const server = new ApolloServer({
schema: makeExecutableSchema({
typeDefs,
resolvers,
resolvers
}),
context: async ({
req,
req
}: {
req: Request & { user: JwtPayloadType }
}): Promise<ApolloContextType> => {
@ -34,11 +34,11 @@ const server = new ApolloServer({
return { db, user }
},
debug: false,
debug: false
})
server.applyMiddleware({ app })
app.listen(4000, () => {
console.log("Server ready at http://localhost:4000")
console.log('Server ready at http://localhost:4000')
})

View File

@ -2,16 +2,16 @@ import {
checkRightsAndResolve,
getForm,
getFormAuthor,
getForms,
} from "../controllers"
getForms
} from '../controllers'
import {
Form,
QueryFormArgs,
QuestionResolvers,
Resolver,
AnswerResolvers,
} from "../typeDefs/typeDefs.gen"
import { ApolloContextType } from "../types"
AnswerResolvers
} from '../typeDefs/typeDefs.gen'
import { ApolloContextType } from '../types'
const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
_,
@ -26,13 +26,10 @@ const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
return await checkRightsAndResolve({
user,
expected: {
id: {
n: 0,
self: false,
},
admin: false,
id: 0,
self: false
},
controller: getFormById,
controller: getFormById
})
} catch (err) {
return err
@ -53,13 +50,10 @@ const formsQuery: Resolver<Form[], {}, ApolloContextType> = async (
>({
user,
expected: {
id: {
n: 0,
self: true,
},
admin: false,
id: 0,
self: true
},
controller: getFormsByUserId,
controller: getFormsByUserId
})
} catch (err) {
return err
@ -69,19 +63,19 @@ const formsQuery: Resolver<Form[], {}, ApolloContextType> = async (
const QuestionResolver: QuestionResolvers = {
__resolveType(obj: any) {
if (obj.type) {
return "ChoisesQuestion"
return 'ChoisesQuestion'
}
return "InputQuestion"
},
return 'InputQuestion'
}
}
const AnswerResolver: AnswerResolvers = {
__resolveType(obj) {
if (obj.type == "CHOISE") return "ChoiseAnswer"
if (obj.type == "INPUT") return "InputAnswer"
if (obj.type == 'CHOISE') return 'ChoiseAnswer'
if (obj.type == 'INPUT') return 'InputAnswer'
return null
},
}
}
export { formQuery, formsQuery, QuestionResolver, AnswerResolver }

View File

@ -1,13 +1,14 @@
import { ApolloError, UserInputError } from 'apollo-server-express'
import { UserInputError } from 'apollo-server-express'
import { tokenGenerate } from '../controllers/auth'
import { sendToken } from '../mailer'
import { checkRightsAndResolve, sendTokenEmail } from '../controllers/auth'
import { createUser, findUserBy } from '../db'
import {
MutationLoginArgs,
MutationRegisterArgs,
Resolver,
LoginResult,
User,
LoginResult
QueryUserArgs
} from '../typeDefs/typeDefs.gen'
import { ApolloContextType } from '../types'
@ -18,19 +19,11 @@ const loginResolver: Resolver<
MutationLoginArgs
> = async (_, { email }, { db }) => {
try {
const user = await db.user.findOne({
where: {
email
}
})
const user = await findUserBy(db, { email })
if (!user) throw new UserInputError('No such user')
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")
await sendTokenEmail(email, user)
return { success: true }
} catch (err) {
@ -45,15 +38,9 @@ const registerResolver: Resolver<
MutationRegisterArgs
> = async (_, { email, name }, { db }) => {
try {
const user = await db.user.create({
data: { email, name }
})
const user = await createUser(db, { email, name })
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")
await sendTokenEmail(email, user)
return { success: true }
} 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 }

View File

@ -1,24 +1,29 @@
import { ApolloContextType } from "../types"
import { Resolvers } from "../typeDefs/typeDefs.gen"
import { ApolloContextType } from '../types'
import { Resolvers } from '../typeDefs/typeDefs.gen'
import {
formQuery as form,
QuestionResolver as Question,
AnswerResolver as Answer,
formsQuery as forms,
} from "./Form"
import { loginResolver as login, registerResolver as register } from "./User"
formsQuery as forms
} from './Form'
import {
loginResolver as login,
registerResolver as register,
userResolver as user
} from './User'
const resolvers: Resolvers<ApolloContextType> = {
Query: {
form,
forms,
user
},
Mutation: {
login,
register
},
Question,
Answer,
Answer
}
export default resolvers

View File

@ -1,6 +1,7 @@
type Query {
forms: [Form!]!
form(id: Int!): Form
user(id: Int): User
}
type Mutation {
@ -77,7 +78,6 @@ type User {
email: String!
id: Int!
forms: [Form!]
token: String
}
type LoginResult {

View File

@ -1,5 +1,4 @@
import { PrismaClient } from "@prisma/client"
import {} from "express-jwt"
import { PrismaClient } from '@prisma/client'
export type ApolloContextType = {
db: PrismaClient