Base setup

This commit is contained in:
Barry Low committed 2018-12-07 19:14:14 -08:00
commit beeccd7e3d
40 files changed
+7288

No files matched your search

+130
View File
@@ -0,0 +1,130 @@
import http from 'http'
import { ApolloServer, makeExecutableSchema } from 'apollo-server-express'
import { applyMiddleware as applyGraphQLMiddleware } from 'graphql-middleware'
import { moduleAuth } from './middleware'
import { logger } from './logger'
/**
*
* @description Creates an Apollo Server. Setup based on `vue-cli-plugin-apollo`.
* @param {Object} app Express application
* @param {Object} options Apollo options
* @returns {Object} HTTP Server
*/
export default function createApolloServer(
app,
{
// Main options
graphqlEndpoint = '',
typeDefs = {},
resolvers = {},
schemaDirectives = {},
directiveResolvers = {},
graphqlMiddlewares = [],
dataSources = () => ({}),
context = () => ({}),
// Subscriptions
subscriptionsEndpoint = '',
wsMiddlewares = [],
// Mocks
mocks,
// Apollo Engine
engineKey = '',
// HTTP options
cors = true,
timeout = 120000,
// Extra options for Apollo Server
apolloServerOptions = {},
}
) {
const schema = makeExecutableSchema({
typeDefs,
resolvers,
schemaDirectives,
directiveResolvers,
resolverValidationOptions: {
requireResolversForResolveType: false,
},
})
// Apollo server options
const options = {
...apolloServerOptions,
schema: applyGraphQLMiddleware(schema, ...graphqlMiddlewares),
tracing: true,
cacheControl: true,
introspection: true,
engine: engineKey ? { apiKey: engineKey } : false,
dataSources,
// Resolvers context in POST requests
context: async ({ req, connection }) => {
let contextData
try {
if (connection) {
contextData = { ...connection.context }
} else {
contextData = await context({ req, request: req })
}
} catch (err) {
logger.error(err)
throw err
}
return contextData
},
// Resolvers context in WebSocket requests
subscriptions: {
path: subscriptionsEndpoint,
onConnect: async (connection, websocket) => {
const { authorization, userid } = connection
let contextData = {}
try {
// Simulate `req` object for auth
const req = { headers: { authorization, userid } }
// Call all middlewares in order and modify `req`
await new Promise((resolve, reject) =>
wsMiddlewares.reduceRight(
(acc, m) => err => (err ? reject(err) : m(req, null, acc)),
err => (err ? reject(err) : resolve())
)()
)
contextData = await context({
connection,
websocket,
request: req,
req,
})
} catch (err) {
logger.error(err)
}
return contextData
},
},
}
// Apollo Server
const server = new ApolloServer(options)
// Express middleware
server.applyMiddleware({
moduleAuth,
app,
cors,
path: graphqlEndpoint,
// gui: {
// endpoint: graphqlEndpoint,
// subscriptionEndpoint: graphqlSubscriptionsPath,
// },
})
// Create HTTP server and add subscriptions
const httpServer = http.createServer(app)
httpServer.setTimeout(timeout)
server.installSubscriptionHandlers(httpServer)
return httpServer
}
+153
View File
@@ -0,0 +1,153 @@
var jwt = require('jsonwebtoken')
var axios = require('axios')
import { logger } from '../logger'
const sendTeamMemberInvite = function(email, team) {
const dev = process.env.NODE_ENV === 'development' ? true : false
logger.info(`sendTeamMemberInvite email|team: ${email} | ${team}`)
const API_KEY = process.env.SG_APIKEY
const token = jwt.sign({ email: email, team: team.slug }, API_KEY, { expiresIn: '7d' })
let origin = 'https://teams.advancedalgos.net'
const params = '/activate-team-membership/'
if (dev){
origin = 'http://localhost:3001'
}
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : origin,
'Access-Control-Allow-Credentials': 'true'
};
const data = JSON.stringify({
"personalizations": [
{
"to": [
{
"email": email
}
],
dynamic_template_data: {
"aateaminvitelink": origin + params + token,
"aateamname": team.name,
"subject": "INVITATION: Join team " + team.name
},
"subject": "INVITATION: Join team " + team.name
}
],
"from": {
"email": "noreply@advancedalgos.net",
"name": "Advanced Algos Teams"
},
"reply_to": {
"email": "feedback@advancedalgos.net",
"name": "Advanced Algos Teams"
},
"template_id": process.env.SG_INVITE_EMAILID
})
let sendVerify = axios({
method: 'post',
url: 'https://api.sendgrid.com/v3/mail/send',
data: data,
headers:{
'content-type': 'application/json',
'authorization': 'Bearer ' + API_KEY
}
})
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
return 'Success'
} else {
throw response.data.errors[0].message
}
})
.catch(function (error) {
return `${error.status}-${error.response.data.errors[0].message}`
})
return sendVerify
}
const sendTeamCreateConfirmation = function(email, teamName, botName) {
const dev = process.env.NODE_ENV === 'development' ? true : false
logger.info(`sendTeamCreateConfirmation email|teamName|botName: ${email} | ${teamName} | ${botName}`)
const API_KEY = process.env.SG_APIKEY
let origin = 'https://teams.advancedalgos.net'
if (dev){
origin = 'http://localhost:3001'
}
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : origin,
'Access-Control-Allow-Credentials': 'true'
};
const data = JSON.stringify({
"personalizations": [
{
"to": [
{
"email": email
}
],
dynamic_template_data: {
"aadeveloplink": "https://develop.advancedalgos.net/index.html",
"aateamname": teamName,
"aabotname": botName,
"subject": "Team " + teamName + " has been created!"
},
"subject": "Team " + teamName + " has been created!"
}
],
"from": {
"email": "noreply@advancedalgos.net",
"name": "Advanced Algos Teams"
},
"reply_to": {
"email": "feedback@advancedalgos.net",
"name": "Advanced Algos Teams"
},
"template_id": process.env.SG_TEAMCREATE_EMAILID
})
let sendTeamCreation = axios({
method: 'post',
url: 'https://api.sendgrid.com/v3/mail/send',
data: data,
headers:{
'content-type': 'application/json',
'authorization': 'Bearer ' + API_KEY
}
})
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
return 'Success'
} else {
throw response.data.errors[0].message
}
})
.catch(function (error) {
return `${error.status}-${error.response.data.errors[0].message}`
})
return sendTeamCreation
}
const verifyInviteToken = async function(token) {
const API_KEY = process.env.SG_APIKEY
let verifiedToken
try {
verifiedToken = await jwt.verify(token, API_KEY, {maxAge: '7d'})
} catch(err) {
if (err.name === "TokenExpiredError"){
throw new Error ("Error: Token Expired. Please request new invitation or apply to the team again")
} else {
throw new Error (`Error: Token error - ${err.message}`)
}
}
logger.info(`verifyInviteToken: ${verifiedToken}`)
return verifiedToken
}
module.exports = { sendTeamMemberInvite, sendTeamCreateConfirmation, verifyInviteToken }
+49
View File
@@ -0,0 +1,49 @@
import { ApolloError } from 'apollo-server-express'
import { inspect } from 'util'
import { logger } from '../logger'
export {
ApolloError,
AuthenticationError,
ForbiddenError,
SyntaxError,
UserInputError,
ValidationError,
} from 'apollo-server-express'
export const formatError = (error) => {
// This can be used to send errors to third
// party services like Sentry or Stackdriver
logger.info('formatError')
logger.error(JSON.parse(JSON.stringify(inspect(error))))
const originalError = searchOriginalError(error)
logger.error('originalError')
logger.error(originalError)
const { message, code } = originalError
return { message, code}
}
const searchOriginalError = (error) => {
if (error.originalError) {
logger.error('Original Error')
logger.error(error.originalError)
return error.originalError
}
if (error.errors) {
logger.error('Errors')
logger.error(JSON.parse(JSON.stringify(inspect(error.errors))))
return error.errors.map(searchOriginalError)[0]
}
logger.error('searchOriginalErrors')
logger.error(JSON.parse(JSON.stringify(inspect(error))))
return error;
}
// Define custom Apollo errors here
export class ExternalServiceError extends ApolloError {
constructor(message) {
super(message, 'EXTERNAL_SERVICE_UNAVAILABLE')
Object.defineProperty(this, 'name', { value: this.constructor.name })
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"errors": [
{
"code": 401,
"message": "Wait, you're not supposed to be here, go through the gate as everyone else"
}
]
}
@@ -0,0 +1,17 @@
export const createMember = async function (ctx, info, authId) {
logger.info('createMember', authId)
const member = await ctx.db.mutation.upsertMember({
where: {
authId: authId,
},
create: {
authId: authId,
alias: idToken.nickname
},
update: {
authId: authId,
alias: idToken.nickname
}
}, info)
return member
}
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,188 @@
import axios from 'axios'
import { ApolloError } from 'apollo-server-express'
import { getUser } from '../../../middleware/getMember'
import { sendTeamMemberInvite, sendTeamCreateConfirmation, verifyInviteToken } from '../../../email/sendgrid'
import TEAMS_CONNECTIONS_FRAGMENT from '../../fragments/TeamsConnectionsFragment'
import TEAMS_FRAGMENT from '../../fragments/TeamsFragment'
import TEAM_FB_FRAGMENT from '../../fragments/TeamFBFragment'
import { logger, AuthenticationError, ServiceUnavailableError, DatabaseError, ConflictError } from '../../../logger'
export const resolvers = {
Mutation: {
async sendMemberInviteSG(parent, { email, teamId }, ctx, info) {
const team = await ctx.db.query.team({ where: { id: teamId } }, TEAMS_FRAGMENT)
const addMember = await ctx.db.mutation.upsertTeamMembers({
where:{email: email},
create:{role:'MEMBER', email:email, team: {connect: {id: teamId}}, status:{create:{status: 'INVITED', reason: `Invited by ${team.members[0].member.alias}`}}},
update:{role: 'MEMBER', email: email, team: {connect: {id: teamId}}, status:{create:{status: 'INVITED', reason: `Invite resent by ${team.members[0].member.alias}`}}}},
`{ id }`)
const sendInvite = await sendTeamMemberInvite(email, team)
return sendInvite
},
async verifyTeamInvite(parent, { token }, ctx, info) {
let verifiedToken = null
let team = null
try {
verifiedToken = await verifyInviteToken(token)
team = {
email: verifiedToken.email,
team: {
slug: verifiedToken.team
}
}
logger.info('verifyTeamInvite.token: ', await verifiedToken)
} catch (err) {
logger.debug('verifyTeamInvite. err: ', err)
throw new DatabaseError(err.message)
}
return team
},
async createTeam(parent, { name, slug, botName, botSlug }, ctx, info) {
logger.info('createTeam ctx.request.user:')
logger.info(ctx.request.headers.userid)
const authId = ctx.request.headers.userid
if (!authId) {
throw new AuthenticationError()
}
const userData = await getUser(authId)
logger.info('userData:')
logger.info(JSON.stringify(await userData))
const alias = await userData.data.users_User.alias
const email = await userData.data.users_User.email
const avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
const banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
const createTeamUrl = encodeURI(`${slug}/${name}/${alias}/${botSlug}/${botName}`)
logger.info('createTeamUrl:')
logger.info(JSON.stringify(await createTeamUrl))
const platformUrl = 'https://charts-dev.advancedalgos.net/AABrowserAPI/newTeam/'
// const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
logger.info(`${platformUrl}${createTeamUrl}/${authId}`)
const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}/${authId}/${process.env.AAWEB_TEAM_SHARED_SECRET}`)
.then((result) => {
console.log('createPlatformTeam result:', result.data)
if(result.data.message === 'Team Name already taken'){
return { error: 'Team already exist on AA Cloud.', code: 409 }
}
if(result.data.result === 'Fail'){
return { error: `${result.data.message} - Creating team on AA Cloud has failed`, code: 404 }
}
return result
})
logger.info('createPlatformTeam')
logger.info(await createPlatformTeam)
logger.info('createPlatformTeam Error')
logger.error(await createPlatformTeam.error)
logger.info('createPlatformTeam Code')
logger.error(await createPlatformTeam.code)
// if (await createPlatformTeam.error && await createPlatformTeam.code === 404) throw new ApolloError(await createPlatformTeam.error, 404)
// if (await createPlatformTeam.error && await createPlatformTeam.code === 409) throw new ApolloError(await createPlatformTeam.error, 409)
const existingMember = await ctx.db.query.member({ where: { authId } }, `{id}`)
.catch((err) => {
logger.debug(err, 'existingMember error: ')
throw new DatabaseError(err)
})
logger.debug('existingMember:')
logger.debug(await existingMember)
let createTeam
if(existingMember !== null && existingMember.id !== null){
logger.info('createTeam with existingMember:')
createTeam = await ctx.db.mutation.createTeam({ data: {name: name, slug: slug, owner: authId, members: {create: {member: {connect: {authId: authId}}, role: 'OWNER', status: { create: { status: 'ACTIVE', reason: `Connected to Team ${name}`}}}}, profile: {create: {avatar: avatar, banner: banner}}, fb: {create: {name: botName, slug: botSlug, kind:'TRADER', avatar: avatar, status: {create: {status: 'ACTIVE', reason: "Cloned on team creation"}}}}, status: {create: {status: 'ACTIVE', reason:"Team created"}}} }, TEAMS_FRAGMENT)
.catch((err) => {
logger.debug(err, 'createTeamMutation error: ')
return new DatabaseError(err)
})
} else {
logger.info('createTeam without existingMember:')
createTeam = await ctx.db.mutation.createTeam({ data: {name: name, slug: slug, owner: authId, members: {create: {member: {create: {authId: authId, alias: alias, visible:'true', status: { create: { status: 'ACTIVE', reason: `Created team ${name}`}}}}, role: 'OWNER', status: { create: { status: 'ACTIVE', reason: `Created with Team ${name}`}}}}, profile: {create: {avatar: avatar, banner: banner}}, fb: {create: {name: botName, slug: botSlug, kind:'TRADER', avatar: avatar, status: {create: {status: 'ACTIVE', reason: "Cloned on team creation"}}}}, status: {create: {status: 'ACTIVE', reason:"Team created"}}} }, TEAMS_FRAGMENT)
.catch((err) => {
logger.debug(err, 'createTeamMutation error: ')
return new DatabaseError(err)
})
}
sendTeamCreateConfirmation(email, name, botName)
return createTeam
},
async updateTeamProfile(parent, { slug, owner, description, motto, avatar, banner }, ctx, info) {
return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar, banner: banner}}}, where:{slug: slug}}, TEAMS_FRAGMENT)
.catch((err) => {
logger.debug('createTeam error: ', err)
throw new DatabaseError(`Team Profile Update Error: ${err}`)
})
},
async updateFB(parent, { fbId, avatar}, ctx, info) {
return ctx.db.mutation.updateFinancialBeings({data:{avatar:avatar}, where:{id:fbId}}, info)
.catch((err) => {
logger.debug('createTeam error: ', err)
throw new DatabaseError(`Update Financial Being Error: ${err}`)
})
},
async deleteTeam(parent, { slug, botSlug }, ctx, info) {
logger.info('deleteTeam ctx.request.user:')
logger.info(ctx.request.headers.userid)
const authId = ctx.request.headers.userid
if (!authId) {
throw new AuthenticationError()
}
logger.info(authId)
logger.info('getUser')
logger.info(getUser)
return getUser(authId)
.then(async result => {
logger.info('deleteTeam axios:')
logger.info(await result)
const alias = await result.data.users_User.alias
// const email = result.data.users_User.email
const deleteTeamUrl = encodeURI(`${slug}/${alias}/${botSlug}`)
logger.info('deleteTeamUrl:')
logger.info(JSON.stringify(await deleteTeamUrl))
const platformUrl = 'https://charts-dev.advancedalgos.net/AABrowserAPI/deleteTeam/'
// const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
logger.info(`${platformUrl}${deleteTeamUrl}/${authId}`)
const deletePlatformTeam = await axios.get(`${platformUrl}${deleteTeamUrl}/${authId}/${process.env.AAWEB_DELETE_TEAM_SHARED_SECRET}`)
.then((result) => {
console.log('deletePlatformTeam result:', result.data)
if(result.data.result === 'Fail'){
throw new DatabaseError(result.data.message)
}
return result
})
.catch(err =>{
logger.debug('deletePlatformTeam err:')
logger.debug(err)
throw new DatabaseError(err)
})
console.log('deletePlatformTeam returned: ', await deletePlatformTeam)
return ctx.db.mutation.deleteTeam({ where: { slug } }, info)
.catch((res) => {
logger.info('deleteTeam error: ', res)
const errors = res.graphQLErrors.map((error) => {
throw new DatabaseError(error.message)
})
})
})
.catch((err) => {
logger.debug('deleteTeam error: ')
throw new DatabaseError(err)
})
}
}
}
Whitespace-only changes.
@@ -0,0 +1,20 @@
import { logger } from '../../../logger'
import { member, owner } from './Member'
import { teams, teamById, teamByName, teamBySlug, teamWithRole, teamsByOwner, teamsByRole } from './Team'
import{ fbByTeamMember } from './TeamMember'
export const resolvers = {
Query: {
member: (parent, arg, ctx, info) => member(parent, arg, ctx, info),
teams: (parent, arg, ctx, info) => teams(parent, arg, ctx, info),
teamById: (parent, arg, ctx, info) => teamById(parent, arg, ctx, info),
teamByName: (parent, arg, ctx, info) => teamByName(parent, arg, ctx, info),
teamBySlug: (parent, arg, ctx, info) => teamBySlug(parent, arg, ctx, info),
teamWithRole: (parent, arg, ctx, info) => teamWithRole(parent, arg, ctx, info),
teamsByOwner: (parent, arg, ctx, info) => teamsByOwner(parent, arg, ctx, info),
teamsByRole: (parent, arg, ctx, info) => teamsByRole(parent, arg, ctx, info),
owner: (parent, arg, ctx, info) => owner(parent, arg, ctx, info),
fbByTeamMember: (parent, arg, ctx, info) => fbByTeamMember(parent, arg, ctx, info)
}
}
@@ -0,0 +1,57 @@
import axios from 'axios'
import { logger, DatabaseError } from '../logger'
export const getMember = async (req, res, next, db) => {
if (!req.headers.userId) return next()
logger.info('getMember ')
logger.info(req.headers.userId)
try {
const member = await getUser(req.headers.userId)
req.user = await member
next()
} catch (err) {
next()
}
}
export const getUser = authId => {
logger.info('getUser MiddleWare')
logger.info(authId)
const API_URL = 'https://app-api.advancedalgos.net/graphql'
return new Promise((resolve, reject) => {
try {
return axios.post(API_URL, {
query: `query users_User($userId: ID!) {
users_User(id: $userId){
id
alias
email
}
}`,
variables: {
userId: authId
}
}, {
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
logger.info('getUser result')
logger.info(res.data)
resolve(res.data)
})
.catch(err => {
logger.info('getUser err')
logger.info(err)
reject(err)
})
} catch (error) {
reject(error)
}
})
}
export default getUser
+6
View File
@@ -0,0 +1,6 @@
import merge from 'lodash.merge'
// import { resolvers as queryResolvers } from './Query'
import { resolvers as mutationResolvers } from './Mutation'
export const resolvers = merge(mutationResolvers)
+48
View File
@@ -0,0 +1,48 @@
# import Query.TeamConnection, Team from "../generated/prisma.graphql"
directive @isAuthenticated on QUERY | FIELD | MUTATION
directive @hasRole(roles: [String]) on QUERY | FIELD | MUTATION
directive @isOwner(type: String) on QUERY | MUTATION
directive @isOwnerOrHasRole(type: String, roles: [String]) on QUERY | MUTATION
type Query {
teams: TeamConnection
teamDetails: [Team!]! @isAuthenticated
teamByName(name: String!): Team
teamBySlug(slug: String!): Team
teamById(teamId: String!): Team
teamWithRole(teamId: String!, role: String!): Team
teamsByOwner: [Team!]! @isAuthenticated
teamsByRole: [Team!]! @isAuthenticated
fbByTeamMember: Team @isAuthenticated
owner: Member @isAuthenticated
member: Member @isAuthenticated
}
type Mutation {
authenticate(idToken: String!): Member
verifyTeamInvite(token: String!): TeamMembers
createTeam(name: String!, slug: String!, botName: String!, botSlug: String!): Team @isAuthenticated
updateTeamProfile(slug: String!, description: String, motto: String, avatar: String, banner: String): Team @isAuthenticated
updateFB(fbId: String!, avatar: String): FinancialBeings @isAuthenticated
deleteTeam(slug: String!, botSlug: String!): Team @isAuthenticated @isOwner(type: "Team")
sendMemberInviteSG(email: String!, teamId: String!): String
confirmMember(token: String!): String
removeTeamMember(teamId: String!, memberId: String!): String
}
fragment MemberInfo on Member {
id
authId
alias
visible
status {
...MemberStatusInfo
}
}
fragment MemberStatusInfo on MemberStatus {
status
reason
createdAt
}
+87
View File
@@ -0,0 +1,87 @@
import '@babel/polyfill'
require('dotenv').config();
import express from 'express'
import createApolloServer from './ApolloServer'
import { formatError } from './errors'
import {
Prisma,
extractFragmentReplacements,
forwardTo
} from 'prisma-binding'
import { makeExecutableSchema } from 'graphql-tools'
import { importSchema } from 'graphql-import'
import parser from 'fast-xml-parser'
import axios from 'axios'
import { resolvers } from './graphql/resolvers'
import { schemaDirectives } from './directives'
import pubsub from './pubsub'
import { logger } from './logger'
import wrongPreshared from './errors/notAllowed.json'
const GRAPHQL_ENDPOINT = '/graphql'
const GRAPHQL_SUBSCRIPTIONS = '/graphql'
const PORT = 4001
const NODE_ENV = 'development'
const db = new Prisma({
fragmentReplacements: extractFragmentReplacements(resolvers),
typeDefs: 'src/generated/prisma.graphql',
endpoint: process.env.PRISMA_ENDPOINT,
secret: process.env.PRISMA_SECRET,
debug: false
})
const app = express()
app.post(GRAPHQL_ENDPOINT, (req, res, next) => {
if (req.headers.preshared === process.env.PRESHARED_GATEWAY_KEY) {
next();
} else {
res.send(wrongPreshared);
}
});
app.post(GRAPHQL_ENDPOINT)
const corsOptions = {
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
const options = {
port: 4001,
cors: corsOptions,
endpoint: '/graphql',
subscriptions: '/graphql',
playground: '/graphiql'
}
const server = createApolloServer(app, {
graphqlEndpoint: GRAPHQL_ENDPOINT,
subscriptionsEndpoint: GRAPHQL_SUBSCRIPTIONS,
apolloServerOptions: { formatError },
typeDefs: importSchema('src/graphql/schema.graphql'),
resolvers,
resolverValidationOptions: { requireResolversForResolveType: false },
schemaDirectives,
context: req => ({
...req ,
token: req.headers ? req.headers : undefined,
user: req.user ? req.user : undefined,
userId: (req.headers && req.headers.userid) ? req.headers.userid : undefined,
db,
pubsub
})
})
server.listen({ port: PORT }, () => {
logger.info(
`🚀 GraphQL Server is running on http://localhost:${PORT}${GRAPHQL_ENDPOINT} in "${NODE_ENV}" mode\n`
)
})
+24
View File
@@ -0,0 +1,24 @@
export class AuthenticationError extends Error {
code = 401
message = 'Not Authenticated - you have to be authenticated to perform this action'
}
export class DatabaseError extends Error {
code = 404
message = `Resource Error: ${this.message}`
}
export class ApolloError extends Error {
code = 409
message = `Resource already exists: ${this.message}`
}
export class WrongArgumentsError extends Error {
code = 400
message = 'Wrong arguments : ' + this.message
}
export class ServiceUnavailableError extends Error {
code = 503
message = 'At least one service is unresponding ' + this.message
}
+33
View File
@@ -0,0 +1,33 @@
import { createLogger, format, transports } from 'winston'
import { inspect } from 'util'
import { AuthenticationError, ApolloError, DatabaseError, WrongArgumentsError, ServiceUnavailableError, ConflictError } from './errors'
class LoggerService {
constructor() {
const winstonTransports = [
new transports.Console({
format: format.combine(
format.colorize(),
format.timestamp({ format: 'YY/MM/DD HH:mm' }),
format.printf(
info => `${info.timestamp} - ${info.level}: ${JSON.parse(JSON.stringify(inspect(info.message)))}`
)
),
}),
]
const logger = createLogger({
level: 'info',
transports: winstonTransports,
exceptionHandlers: winstonTransports,
})
return new Proxy(this, {
get: (target, propKey) => logger[propKey],
})
}
}
export const logger = new LoggerService() // Default logger
export { LoggerService, AuthenticationError, ApolloError, ConflictError, DatabaseError, WrongArgumentsError, ServiceUnavailableError }
+23
View File
@@ -0,0 +1,23 @@
import axios from 'axios'
import { logger, DatabaseError } from '../logger'
export const getMember = async (req, res, next, db) => {
if (!req.headers.userId) return next()
logger.debug('getMember ')
logger.debug(req.headers.userId)
try {
const member = await getUser(req.headers.userId)
req.user = await member
logger.debug('getMember - getUser:')
logger.debug(req.user)
next()
} catch (err) {
logger.debug('getMember - error:')
logger.debug(err)
next()
}
}
export default getMember
+3
View File
@@ -0,0 +1,3 @@
import moduleAuth from './moduleAuth'
export { moduleAuth }
+13
View File
@@ -0,0 +1,13 @@
import { logger } from '../logger'
export const moduleAuth = async (req, res, next, db) => {
if (req.headers.preshared === process.env.PRESHARED_GATEWAY_KEY) {
logger.info('Module authenticated')
next();
} else {
logger.error('Module authentication error')
res.send(wrongPreshared);
}
}
export default moduleAuth
+3
View File
@@ -0,0 +1,3 @@
import { PubSub } from 'graphql-subscriptions'
export default new PubSub()