diff --git a/api/.babelrc b/api/.babelrc
index 1320b9a32..81bfbad3f 100644
--- a/api/.babelrc
+++ b/api/.babelrc
@@ -1,3 +1,7 @@
{
- "presets": ["@babel/preset-env"]
+ "presets": ["@babel/preset-env"],
+ "plugins": [
+ "@babel/plugin-proposal-throw-expressions",
+ ["@babel/plugin-proposal-class-properties", { "loose": true }]
+ ]
}
diff --git a/api/package-lock.json b/api/package-lock.json
index d5e74e85c..8292250ea 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -575,6 +575,20 @@
"@babel/plugin-syntax-async-generators": "^7.0.0"
}
},
+ "@babel/plugin-proposal-class-properties": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz",
+ "integrity": "sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-member-expression-to-functions": "^7.0.0",
+ "@babel/helper-optimise-call-expression": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.1.0",
+ "@babel/plugin-syntax-class-properties": "^7.0.0"
+ }
+ },
"@babel/plugin-proposal-json-strings": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz",
@@ -602,6 +616,16 @@
"@babel/plugin-syntax-optional-catch-binding": "^7.0.0"
}
},
+ "@babel/plugin-proposal-throw-expressions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.0.0.tgz",
+ "integrity": "sha512-CA2EUiwnbXrsdV4hy3jYghm91WaL7zL7xYfu628dyItRr6gylbRxshghGEK/Hhm//rR58N3PBmEeuYqSW57IUQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-throw-expressions": "^7.0.0"
+ }
+ },
"@babel/plugin-proposal-unicode-property-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz",
@@ -620,6 +644,15 @@
"@babel/helper-plugin-utils": "^7.0.0"
}
},
+ "@babel/plugin-syntax-class-properties": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0.tgz",
+ "integrity": "sha512-cR12g0Qzn4sgkjrbrzWy2GE7m9vMl/sFkqZ3gIpAQdrvPDnLM8180i+ANDFIXfjHo9aqp0ccJlQ0QNZcFUbf9w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
"@babel/plugin-syntax-json-strings": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz",
@@ -644,6 +677,15 @@
"@babel/helper-plugin-utils": "^7.0.0"
}
},
+ "@babel/plugin-syntax-throw-expressions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.0.0.tgz",
+ "integrity": "sha512-/5uORdWlPta/ALhI5zKtm0Y9vAYOa7HJMML0OnCGk9XZA4hpGjb0Xjt/OVDCJVawC/4FrlAGCHOaj9BtWeVDvg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
"@babel/plugin-transform-arrow-functions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz",
diff --git a/api/package.json b/api/package.json
index 057991f3d..f50720958 100644
--- a/api/package.json
+++ b/api/package.json
@@ -37,7 +37,10 @@
"winston": "^3.1.0"
},
"devDependencies": {
+ "@babel/plugin-proposal-class-properties": "^7.1.0",
+ "@babel/plugin-proposal-throw-expressions": "^7.0.0",
"graphql-cli": "^2.16.5",
+ "lodash.merge": "^4.6.1",
"npm-run-all": "4.1.3",
"prisma": "^1.18.1"
}
diff --git a/api/src/auth/middleware/getMember.js b/api/src/auth/middleware/getMember.js
deleted file mode 100644
index 7d19b2d6c..000000000
--- a/api/src/auth/middleware/getMember.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const getMember = async (req, res, next, db) => {
- if (!req.user) return next()
- const member = await db.query.member({
- where: { authId: req.user.sub }
- })
- req.user = { user: member }
- next()
-}
-
-module.exports = { getMember }
diff --git a/api/src/auth/validateIdToken.js b/api/src/auth/validateIdToken.js
deleted file mode 100644
index dd0b794b3..000000000
--- a/api/src/auth/validateIdToken.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const jwksClient = require('jwks-rsa')
-const jwt = require('jsonwebtoken')
-const jwks = jwksClient({
- cache: true,
- rateLimit: true,
- jwksRequestsPerMinute: 1,
- jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
-})
-
-const validateIdToken = idToken =>
- new Promise((resolve, reject) => {
- const { header, payload } = jwt.decode(idToken, { complete: true })
- if (!header || !header.kid || !payload) reject(new Error('Invalid Token'))
- jwks.getSigningKey(header.kid, (err, key) => {
- if (err) reject({ error: `Error getting signing key: ${err.message}` })
- jwt.verify(
- idToken,
- key.publicKey,
- { algorithms: ['RS256'] },
- (err, decoded) => {
- if (err) reject('jwt verify error: ' + err.message)
- resolve(decoded)
- }
- )
- })
- })
-
-module.exports = { validateIdToken }
diff --git a/api/src/directives/index.js b/api/src/directives/index.js
index 8e6b925ae..be47f90c1 100644
--- a/api/src/directives/index.js
+++ b/api/src/directives/index.js
@@ -1,13 +1,12 @@
import { SchemaDirectiveVisitor } from 'apollo-server-express'
import _get from 'lodash.get'
-import { logger } from '../logger'
-
-import { AuthenticationError, ForbiddenError } from '../errors'
-import { validateIdToken } from '../auth/validateIdToken'
+import { logger, AuthenticationError } from '../logger'
const memberLocationOnContext = 'request.user'
+const userIdOnContext = 'request.headers.userid'
const bearerAccessToken = 'request.headers.authorization'
+const ctxUserId = ctx => _get(ctx, userIdOnContext)
const ctxMember = ctx => _get(ctx, memberLocationOnContext)
const ctxToken = ctx => _get(ctx, bearerAccessToken)
@@ -29,48 +28,20 @@ const createMember = async (ctx, idToken, info) => {
return member
}
-const isLoggedIn = async ctx => {
- logger.info(`isLoggedIn 0: ${JSON.stringify(ctx.request.headers)}`)
- let member = ctxMember(ctx, memberLocationOnContext)
- let token = ctxToken(ctx, bearerAccessToken)
- let memberToken
- logger.info('isLoggedIn: ', member, token)
- if (!member && token) {
- let scheme, credentials
- const tokenParts = token.split(' ')
- if (tokenParts.length === 2) {
- scheme = tokenParts[0]
- credentials = tokenParts[1]
- }
-
- if (/^Bearer$/i.test(scheme)) {
- token = credentials
- //verify token
- try {
- memberToken = await validateIdToken(token)
- const authId = memberToken.sub
- exists = await ctx.db.query.member({ where: { authId: authId } })
- if (!member && exists === null) {
- member = await createMember(ctx, memberToken).then(res => {
- return res
- })
-
- return member
- }
- return member
- } catch (err) {
- memberToken = false
- }
- }
- }
- if (!member) {
- throw new AuthenticationError('Access token is missing or expired')
- }
+const isUserId = async ctx => {
+ logger.info(`isUserId 0: ${ctx.request.headers.userid}`)
+ logger.info(`isUserId 1: ${ctx.request}`)
+ let member = await ctxUserId(ctx)
+ logger.info(member)
+ if (!member) {
+ throw new AuthenticationError()
+ } else {
return member
+ }
}
-const isRequestingMemberAlsoOwner = ({ ctx, memberId, type, typeId }) =>
- ctx.db.exists[type]({ slug: typeId, owner: memberId })
+const isRequestingMemberAlsoOwner = ({ ctx, memberId, type, teamSlug }) =>
+ ctx.db.exists[type]({ slug: teamSlug, owner: memberId })
const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ authId: memberId })
@@ -89,17 +60,18 @@ const assertAuth = ctx => {
// Directive resolvers (apollo v1 syntax)
export const directiveResolvers = {
isAuthenticated: async (next, source, args, ctx) => {
- let result = await isLoggedIn(ctx)
- logger.info('directive isAuthenticated: ', result)
+ let result = await isUserId(ctx)
+ logger.info('directive isAuthenticated: ')
+ logger.info(await result)
return next(result)
},
hasRole: (next, source, { roles }, ctx) => {
- const { role } = isLoggedIn(ctx)
+ const { role } = isUserId(ctx)
logger.info('directive hasRole: ', role)
if (roles.includes(role)) {
return next()
}
- throw new ForbiddenError('Insufficient permissions')
+ throw new AuthenticationError('Insufficient permissions')
},
isOwner: async (next, source, { type }, ctx) => {
logger.info('directive isOwner: ', source, type, ctx)
@@ -107,47 +79,46 @@ export const directiveResolvers = {
source && source.id
? source
: ctx.request.body.variables ? ctx.request.body.variables : { id: null }
- const user = await isLoggedIn(ctx)
- const memberId = user.sub
+ const userId = await isUserId(ctx)
const isOwner =
type === `Member`
? memberId === typeId
- : await isRequestingMemberAlsoOwner({ ctx, memberId, type, typeId })
+ : await isRequestingMemberAlsoOwner({ ctx, userId, type, typeId })
if (isOwner) {
return next()
}
- throw new ForbiddenError('Insufficient permissions')
+ throw new AuthenticationError('Insufficient permissions')
},
isOwnerOrHasRole: async (next, source, { roles, type }, ctx, ...p) => {
- const { authId: memberId } = await isLoggedIn(ctx)
- logger.info('directive isOwnerOrHasRole 1: ', memberId, roles, type)
- if(memberId === undefined && role=== undefined) throw new Error(`Not logged in`)
+ const userId = await isUserId(ctx)
+ logger.info('directive isOwnerOrHasRole 1: ', userId, roles, type)
+ if(userId === undefined && role=== undefined) throw new Error(`Not logged in`)
if (roles.includes(role)) {
return next()
}
- const { authId: typeId } = ctx.request.body.variables
+ const { teamSlug } = ctx.request.body.variables
const isOwner = await isRequestingMemberAlsoOwner({
ctx,
- memberId,
+ userId,
type,
- typeId
+ teamSlug
})
- logger.info('directive isOwnerOrHasRole 2: ', typeId, memberId, role, isOwner)
+ logger.info('directive isOwnerOrHasRole 2: ', teamSlug, userId, role, isOwner)
if (isOwner) {
return next()
}
const hasRole = await isRequestingMember({
ctx,
- memberId,
+ userId,
type,
- typeId
+ teamSlug
})
if(hasRole){
return next()
}
- throw new ForbiddenError('Insufficient permissions')
+ throw new AuthenticationError('Insufficient permissions')
}
}
diff --git a/api/src/graphql/TeamFBFragment.js b/api/src/graphql/fragments/TeamFBFragment.js
similarity index 90%
rename from api/src/graphql/TeamFBFragment.js
rename to api/src/graphql/fragments/TeamFBFragment.js
index f7030921d..b0f99c664 100644
--- a/api/src/graphql/TeamFBFragment.js
+++ b/api/src/graphql/fragments/TeamFBFragment.js
@@ -1,4 +1,4 @@
-const gql = require('graphql-tag')
+import gql from 'graphql-tag'
const TEAM_FB_FRAGMENT = gql`{
id
diff --git a/api/src/graphql/TeamsConnectionsFragment.js b/api/src/graphql/fragments/TeamsConnectionsFragment.js
similarity index 95%
rename from api/src/graphql/TeamsConnectionsFragment.js
rename to api/src/graphql/fragments/TeamsConnectionsFragment.js
index 5193475e0..f019dd02e 100644
--- a/api/src/graphql/TeamsConnectionsFragment.js
+++ b/api/src/graphql/fragments/TeamsConnectionsFragment.js
@@ -1,4 +1,4 @@
-const gql = require('graphql-tag')
+import gql from 'graphql-tag'
const TEAMS_CONNECTIONS_FRAGMENT = gql`{
edges {
diff --git a/api/src/graphql/TeamsFragment.js b/api/src/graphql/fragments/TeamsFragment.js
similarity index 93%
rename from api/src/graphql/TeamsFragment.js
rename to api/src/graphql/fragments/TeamsFragment.js
index 442829e3c..1dd527af9 100644
--- a/api/src/graphql/TeamsFragment.js
+++ b/api/src/graphql/fragments/TeamsFragment.js
@@ -1,4 +1,4 @@
-const gql = require('graphql-tag')
+import gql from 'graphql-tag'
const TEAMS_FRAGMENT = gql`{
id
diff --git a/api/src/graphql/resolvers/Mutation/Member.js b/api/src/graphql/resolvers/Mutation/Member.js
new file mode 100644
index 000000000..653764d4c
--- /dev/null
+++ b/api/src/graphql/resolvers/Mutation/Member.js
@@ -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
+}
diff --git a/api/src/graphql/resolvers/Mutation/Team.js b/api/src/graphql/resolvers/Mutation/Team.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/api/src/graphql/resolvers/Mutation/TeamMember.js b/api/src/graphql/resolvers/Mutation/TeamMember.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/api/src/graphql/resolvers/Mutation/index.js b/api/src/graphql/resolvers/Mutation/index.js
new file mode 100644
index 000000000..a596e0100
--- /dev/null
+++ b/api/src/graphql/resolvers/Mutation/index.js
@@ -0,0 +1,194 @@
+import axios from 'axios'
+
+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 } 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 Error(err.message)
+ }
+ return team
+ },
+ async createTeam(parent, { name, slug, botName, botSlug }, ctx, info) {
+ logger.info('createTeam ctx.request.user:')
+ logger.info(ctx.request.user)
+
+ const authId = ctx.request.headers.userid
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+
+ return getUser(authId)
+ .then(async result => {
+ logger.info('axios:')
+ logger.info(result)
+
+ const alias = result.data.users_User.alias
+ const email = result.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://develop.advancedalgos.net/AABrowserAPI/newTeam/'
+ // const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
+
+ logger.info(`${platformUrl}${createTeamUrl}/${authId}`)
+ const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}/${authId}`)
+ .then((result) => {
+ console.log('createPlatformTeam result:', result.data)
+ if(result.data.message === 'Team Name already taken'){
+ return result.data.message
+ }
+ if(result.data.result === 'Fail'){
+ return result.data.message
+ }
+ return result
+ })
+ .catch(err =>{
+ logger.debug('createPlatformTeam err:')
+ logger.debug(err)
+ throw new Error(err)
+ })
+ console.log('createPlatformTeam returned: ', await createPlatformTeam)
+ if(await createPlatformTeam === 'Team Name already taken'){
+ return createPlatformTeam
+ }
+
+ const existingMember = await ctx.db.query.member({ where: { authId } }, `{id}`)
+ .catch((err) => {
+ logger.debug(err, 'existingMember error: ')
+ return err
+ })
+
+ logger.info('existingMember:')
+ logger.info(await existingMember)
+
+ let createTeam
+ if(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 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 err
+ })
+ }
+
+ // sendTeamCreateConfirmation(email, name, botName)
+
+ return createTeam
+ })
+ .catch((err) => {
+ logger.debug('createTeam error: ')
+ return err
+ })
+ },
+ 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)
+ return 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)
+ return err
+ })
+ },
+ async deleteTeam(parent, { slug, botSlug }, ctx, info) {
+ logger.info('DeleteTeam resolver')
+ 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://develop.advancedalgos.net/AABrowserAPI/deleteTeam/'
+ // const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
+
+ logger.info(`${platformUrl}${deleteTeamUrl}/${authId}`)
+ const deletePlatformTeam = await axios.get(`${platformUrl}${deleteTeamUrl}/${authId}`)
+ .then((result) => {
+ console.log('deletePlatformTeam result:', result.data)
+ if(result.data.result === 'Fail'){
+ return result.data.message
+ }
+ return result
+ })
+ .catch(err =>{
+ logger.debug('deletePlatformTeam err:')
+ logger.debug(err)
+ throw new Error(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) => {
+ return error.message
+ })
+ })
+ })
+ .catch((err) => {
+ logger.debug('deleteTeam error: ')
+ return err
+ })
+ }
+ }
+}
diff --git a/api/src/graphql/resolvers/Query/Member.js b/api/src/graphql/resolvers/Query/Member.js
new file mode 100644
index 000000000..2ca9d69d6
--- /dev/null
+++ b/api/src/graphql/resolvers/Query/Member.js
@@ -0,0 +1,30 @@
+import { logger, AuthenticationError, DatabaseError } from '../../../logger'
+
+export const member = async (parent, arg, ctx, info) => {
+ logger.info(' --> resolver.member')
+ logger.info(ctx.request)
+ const authId = ctx.request.headers.userid
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+ return ctx.db.query.member({ where: { authId } }, info)
+ .catch(err => {
+ logger.debug('resolver.member error: ')
+ logger.debug(err)
+ throw new DatabaseError(`Member Data Error: ${err.message}`)
+ })
+}
+
+export const owner = async (parent, args, ctx, info) => {
+ logger.info('resolver.query.owner ctx: ')
+ const authId = ctx.request.userId
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+ return ctx.db.query.member({ where: { authId: authId } }, info)
+ .catch(err => {
+ logger.debug('resolver.owner error: ')
+ logger.debug(err)
+ throw new DatabaseError(`Member Data Error: ${err.message}`)
+ })
+}
diff --git a/api/src/graphql/resolvers/Query/Team.js b/api/src/graphql/resolvers/Query/Team.js
new file mode 100644
index 000000000..4961888e5
--- /dev/null
+++ b/api/src/graphql/resolvers/Query/Team.js
@@ -0,0 +1,51 @@
+import { logger } from '../../../logger'
+
+import TEAMS_CONNECTIONS_FRAGMENT from '../../fragments/TeamsConnectionsFragment'
+import TEAMS_FRAGMENT from '../../fragments/TeamsFragment'
+
+export const teams = async (parent, args, ctx, info) => {
+ logger.info('teams')
+ console.log('teams')
+ return ctx.db.query.teamsConnection({}, TEAMS_CONNECTIONS_FRAGMENT)
+}
+
+export const teamById = async (parent, { id }, ctx, info) => {
+ return ctx.db.query.team({ where: { id } }, info)
+}
+
+export const teamByName = async (parent, { name }, ctx, info) => {
+ return ctx.db.query.team({ where: { name: name } }, `{ name }`)
+}
+
+export const teamWithRole = async (parent, { teamId, role }, ctx, info) => {
+ return ctx.db.query.teamsConnection({where: {AND: [{id: teamId},{members_some:{role: role}}]}, first:1}, info)
+}
+
+export const teamsByOwner = async (parent, args, ctx, info) => {
+ logger.info('teamsByOwner')
+ const authId = ctx.request.headers.userid
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+ return ctx.db.query.teams({where: { owner: authId }, orderBy:'updatedAt_DESC'}, TEAMS_FRAGMENT)
+}
+
+export const teamsByRole = async (parent, args, ctx, info) => {
+ const authId = ctx.request.headers.userid
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+ let teamAdmin
+ try {
+ teamAdmin= await ctx.db.query.teams({where: {members_some: {AND: [{member: {authId: authId}, role_not:'MEMBER'}]}}}, TEAMS_FRAGMENT)
+ } catch (err) {
+ logger.debug('teamsByRole error: ')
+ logger.debug(err)
+ const errors = res.graphQLErrors.map((error) => {
+ return error.message
+ })
+ return errors
+ }
+ logger.info('teamsByRole teamAdmin: ', teamAdmin)
+ return teamAdmin
+}
diff --git a/api/src/graphql/resolvers/Query/TeamMember.js b/api/src/graphql/resolvers/Query/TeamMember.js
new file mode 100644
index 000000000..9126c9c5d
--- /dev/null
+++ b/api/src/graphql/resolvers/Query/TeamMember.js
@@ -0,0 +1,12 @@
+import { logger } from '../../../logger'
+
+export const fbByTeamMember = async (parent, args, ctx, info) => {
+ logger.info('fbByTeamMember: ', args, ctx.request, ctx.request.res.req.user)
+ const authId = ctx.request.headers.userid
+ if (!authId) {
+ throw new AuthenticationError()
+ }
+ let teamMemberFB = await ctx.db.query.teams({where: {members_some: {AND: [{member: {authId: authId}}]}}, orderBy: 'updatedAt_DESC'}, TEAM_FB_FRAGMENT)
+ logger.info('fbByTeamMember response: ', await teamMemberFB[0])
+ return teamMemberFB[0]
+}
diff --git a/api/src/graphql/resolvers/Query/index.js b/api/src/graphql/resolvers/Query/index.js
new file mode 100644
index 000000000..5616f8cbb
--- /dev/null
+++ b/api/src/graphql/resolvers/Query/index.js
@@ -0,0 +1,19 @@
+import { logger } from '../../../logger'
+
+import { member, owner } from './Member'
+import { teams, teamById, teamByName, 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),
+ 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)
+ }
+}
diff --git a/api/src/graphql/resolvers/index.js b/api/src/graphql/resolvers/index.js
new file mode 100644
index 000000000..543ab4e32
--- /dev/null
+++ b/api/src/graphql/resolvers/index.js
@@ -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(queryResolvers, mutationResolvers)
diff --git a/api/src/schema.graphql b/api/src/graphql/schema.graphql
similarity index 72%
rename from api/src/schema.graphql
rename to api/src/graphql/schema.graphql
index 2be3053e3..2095882bb 100644
--- a/api/src/schema.graphql
+++ b/api/src/graphql/schema.graphql
@@ -1,4 +1,4 @@
-# import Query.TeamConnection, Team from "./generated/prisma.graphql"
+# import Query.TeamConnection, Team from "../generated/prisma.graphql"
directive @isAuthenticated on QUERY | FIELD | MUTATION
directive @hasRole(roles: [String]) on QUERY | FIELD | MUTATION
@@ -11,12 +11,11 @@ type Query {
teamByName(name: String!): Team
teamById(teamId: String!): Team
teamWithRole(teamId: String!, role: String!): Team
- teamsByOwner(ownerId: String!): [Team!]! @isAuthenticated
+ teamsByOwner: [Team!]! @isAuthenticated
teamsByRole: [Team!]! @isAuthenticated
fbByTeamMember: Team @isAuthenticated
owner: Member @isAuthenticated
- currentMember: Member @isAuthenticated
- member(authId: String!): Member @isAuthenticated
+ member: Member @isAuthenticated
}
type Mutation {
@@ -25,7 +24,7 @@ type Mutation {
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!): Team @isAuthenticated @isOwner(type: "Team")
+ 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
@@ -35,18 +34,14 @@ fragment MemberInfo on Member {
id
authId
alias
- isActive
- profile {
- ...MemberProfileInfo
+ visible
+ status {
+ ...MemberStatusInfo
}
}
-fragment MemberProfileInfo on MemberProfile {
- firstName
- lastName
- email
- avatar
- role {
- name
- }
+fragment MemberStatusInfo on MemberStatus {
+ status
+ reason
+ createdAt
}
diff --git a/api/src/index.js b/api/src/index.js
index 47bb9435e..11ed3ea81 100644
--- a/api/src/index.js
+++ b/api/src/index.js
@@ -13,17 +13,10 @@ import { importSchema } from 'graphql-import'
import parser from 'fast-xml-parser'
import axios from 'axios'
-import checkJwt from './auth/middleware/jwt'
-import { getMember } from './auth/middleware/getMember'
-import { validateIdToken } from './auth/validateIdToken'
+import { resolvers } from './graphql/resolvers'
+
import { schemaDirectives } from './directives'
-import { sendTeamMemberInvite, sendTeamCreateConfirmation, verifyInviteToken } from './email/sendgrid'
-
-import TEAMS_FRAGMENT from './graphql/TeamsFragment'
-import TEAMS_CONNECTIONS_FRAGMENT from './graphql/TeamsConnectionsFragment'
-import TEAM_FB_FRAGMENT from './graphql/TeamFBFragment'
-
import pubsub from './pubsub'
import { logger } from './logger'
@@ -32,286 +25,6 @@ const GRAPHQL_SUBSCRIPTIONS = '/graphql'
const PORT = 4001
const NODE_ENV = 'development'
-const createMember = async function (ctx, info, idToken) {
- logger.info('createMember', idToken)
- const member = await ctx.db.mutation.upsertMember({
- where: {
- authId: idToken.sub,
- },
- create: {
- authId: idToken.sub,
- alias: idToken.nickname
- },
- update: {
- authId: idToken.sub,
- alias: idToken.nickname
- }
- }, info)
- return member
-}
-
-const ctxMember = ctx => ctx.request.user
-
-const resolvers = {
- Query: {
- async member(parent, arg, ctx, info) {
- logger.info('member: ', parent, arg)
- return ctx.db.query.member({ where: { authId: arg.authId } }, info)
- },
- async currentMember(parent, args, ctx, info) {
- logger.info('currentMember: ', ctx.request.res.req.user, ctx.token)
- const authId = ctx.request.res.req.user.sub
-
- return ctx.db.query.member({ where: { authId } }, info)
- },
- teams(parent, args, ctx, info) {
- logger.info('teams: ', ctx.request.res)
- return ctx.db.query.teamsConnection({}, TEAMS_CONNECTIONS_FRAGMENT)
- },
- async teamById(parent, { id }, ctx, info) {
- return ctx.db.query.team({ where: { id } }, info)
- },
- async teamByName(parent, { name }, ctx, info) {
- return ctx.db.query.team({ where: { name: name } }, `{ name }`)
- },
- async teamWithRole(parent, { teamId, role }, ctx, info) {
- return ctx.db.query.teamsConnection({where: {AND: [{id: teamId},{members_some:{role: role}}]}, first:1}, info)
- },
- async teamsByOwner(parent, { ownerId }, ctx, info) {
- return ctx.db.query.teams({where: { owner: ownerId }, orderBy:'updatedAt_DESC'}, TEAMS_FRAGMENT)
- },
- async teamsByRole(parent, args, ctx, info) {
- const authId = ctx.request.user.sub
- let teamAdmin
- try {
- teamAdmin= await ctx.db.query.teams({where: {members_some: {AND: [{member: {authId: authId}, role_not:'MEMBER'}]}}}, TEAMS_FRAGMENT)
- } catch (err) {
- logger.debug('teamsByRole error: ')
- logger.debug(err)
- const errors = res.graphQLErrors.map((error) => {
- return error.message
- })
- return errors
- }
- logger.info('teamsByRole teamAdmin: ', teamAdmin)
- return teamAdmin
- },
- async fbByTeamMember(parent, args, ctx, info) {
- logger.info('fbByTeamMember: ', args, ctx.request, ctx.request.res.req.user)
- const authId = ctx.request.user.sub
- let teamMemberFB = await ctx.db.query.teams({where: {members_some: {AND: [{member: {authId: authId}}]}}, orderBy: 'updatedAt_DESC'}, TEAM_FB_FRAGMENT)
- logger.info('fbByTeamMember response: ', await teamMemberFB[0])
- return teamMemberFB[0]
- },
- async owner(parent, args, ctx, info) {
- logger.info('resolver.query.owner ctx: ', ctxMember(ctx))
- return ctx.db.query.member({ where: { id: ctxMember(ctx).authId } }, info)
- .catch(err => {
- logger.debug('createTeam error: ', err)
- const errors = res.graphQLErrors.map((error) => {
- return error.message
- })
- })
- }
- },
- Mutation: {
- async authenticate(parent, { idToken }, ctx, info) {
- let memberToken = null
- try {
- memberToken = await validateIdToken(idToken)
- logger.info('authenticate.memberToken: ', await memberToken)
- } catch (err) {
- logger.debug('authenticat.validateIdToken err: ', err)
- throw new Error(err.message)
- }
- const authId = memberToken.sub
- let member = await ctx.db.query.member({ where: { authId } }, info)
-
- if (!member) {
- try {
- return createMember(ctx, info, memberToken)
- } catch (error) {
- throw new Error(error.message)
- }
- }
- return member
- },
- 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 Error(err.message)
- }
- return team
- },
- async createTeam(parent, { name, slug, botName, botSlug }, ctx, info) {
- logger.info('createTeam ctx.request.user:')
- logger.info(ctx.request.user)
-
- const authId = ctx.request.user.sub
-
- const encodedAuthId = encodeURI(authId)
- const encodedURL = `https://users-api.advancedalgos.net/graphql?query=%7B%0A%20%20userByAuthId(authId:%20%22${authId}%22)%20%7B%0A%20%20%20%20id%0A%20%20%20%20email%0A%20%20%20%20alias%0A%20%20%7D%0A%7D%0A`
- const decodedURL = decodeURI(encodedURL)
- return getUser(authId)
- .then(async result => {
- logger.info('axios:')
- logger.info(result)
-
- const alias = result.data.users_UserByAuthId.alias
- const email = result.data.users_UserByAuthId.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://develop.advancedalgos.net/AABrowserAPI/teamSetup/'
- // const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
-
- logger.info(`${platformUrl}${createTeamUrl}/${authId}`)
- const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}/${authId}`)
- .then((result) => {
- console.log('createPlatformTeam result:', result.data)
- if(result.data.message === 'Team Name already taken'){
- return result.data.message
- }
- if(result.data.result === 'Fail'){
- return result.data.message
- }
- return result
- })
- .catch(err =>{
- logger.debug('createPlatformTeam err:')
- logger.debug(err)
- throw new Error(err)
- })
- console.log('createPlatformTeam returned: ', await createPlatformTeam)
- if(await createPlatformTeam === 'Team Name already taken'){
- return createPlatformTeam
- }
-
- const existingMember = await ctx.db.query.member({ where: { authId } }, `{id}`)
- .catch((err) => {
- logger.debug(err, 'existingMember error: ')
- return err
- })
-
- logger.info('existingMember:')
- logger.info(await existingMember)
-
- let createTeam
- if(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 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 err
- })
- }
-
- // sendTeamCreateConfirmation(email, name, botName)
-
- return createTeam
- })
- .catch((err) => {
- logger.debug('createTeam error: ')
- return err
- })
- },
- 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)
- return 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)
- return err
- })
- },
- async deleteTeam(parent, { slug }, ctx, info) {
- return ctx.db.mutation.deleteTeam({ where: { slug } }, info)
- .catch((res) => {
- logger.info('deleteTeam error: ', res)
- const errors = res.graphQLErrors.map((error) => {
- return error.message
- })
- })
- }
- }
-}
-
-const getUser = authId => {
- logger.info('getUser')
- logger.info(authId)
- const API_URL = 'https://app-api.advancedalgos.net/graphql'
- return new Promise(resolve => {
- try {
- const result = axios.post(API_URL, {
- query: `query users_UserByAuthId($authId: String!) {
- users_UserByAuthId(authId: $authId){
- id
- alias
- email
- }
- }`,
- variables: {
- authId: authId
- }
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- })
- .then(result => {
- logger.info('getUser result')
- logger.info(result.data)
- resolve(result.data)
- })
- .catch(err => {
- logger.info('getUser err')
- logger.info(err)
- throw new Error(err)
- })
-
- } catch (error) {
- resolve(error)
- }
- })
-}
-
const db = new Prisma({
fragmentReplacements: extractFragmentReplacements(resolvers),
typeDefs: 'src/generated/prisma.graphql',
@@ -322,20 +35,7 @@ const db = new Prisma({
const app = express()
-const connectionMiddlewares = [
- checkJwt,
- function (err, req, res, next) {
- logger.info('checkJwt: ', err, req.headers, req.user)
- if (err) {
- return res.status(201).send(err.message)
- } else {
- next()
- }
- },
- // (req, res, done) => getMember(req, res, done, db)
-]
-
-app.post(GRAPHQL_ENDPOINT, ...connectionMiddlewares)
+app.post(GRAPHQL_ENDPOINT)
const corsOptions = {
"origin": "*",
@@ -355,16 +55,16 @@ const options = {
const server = createApolloServer(app, {
graphqlEndpoint: GRAPHQL_ENDPOINT,
subscriptionsEndpoint: GRAPHQL_SUBSCRIPTIONS,
- wsMiddlewares: connectionMiddlewares,
apolloServerOptions: { formatError },
- typeDefs: importSchema('src/schema.graphql'),
+ typeDefs: importSchema('src/graphql/schema.graphql'),
resolvers,
resolverValidationOptions: { requireResolversForResolveType: false },
schemaDirectives,
context: req => ({
...req ,
- token: req.headers,
- user: req.user,
+ token: req.headers ? req.headers : undefined,
+ user: req.user ? req.user : undefined,
+ userId: (req.headers && req.headers.userid) ? req.headers.userid : undefined,
db,
pubsub
})
@@ -375,5 +75,3 @@ server.listen({ port: PORT }, () => {
`🚀 GraphQL Server is running on http://localhost:${PORT}${GRAPHQL_ENDPOINT} in "${NODE_ENV}" mode\n`
)
})
-
-module.exports= { createMember }
diff --git a/api/src/logger/errors.js b/api/src/logger/errors.js
new file mode 100644
index 000000000..654dc98ef
--- /dev/null
+++ b/api/src/logger/errors.js
@@ -0,0 +1,19 @@
+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 not found : ' + 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
+}
diff --git a/api/src/logger/index.js b/api/src/logger/index.js
index 3ed2a8e70..2a68e3bfc 100644
--- a/api/src/logger/index.js
+++ b/api/src/logger/index.js
@@ -1,6 +1,8 @@
import { createLogger, format, transports } from 'winston'
import { inspect } from 'util'
+import { AuthentificationError, DatabaseError, WrongArgumentsError, ServiceUnavailableError } from './errors'
+
class LoggerService {
constructor() {
const winstonTransports = [
@@ -28,4 +30,4 @@ class LoggerService {
}
export const logger = new LoggerService() // Default logger
-export { LoggerService }
+export { LoggerService, AuthentificationError, DatabaseError, WrongArgumentsError, ServiceUnavailableError }
diff --git a/api/src/middleware/getMember.js b/api/src/middleware/getMember.js
new file mode 100644
index 000000000..1a4498d45
--- /dev/null
+++ b/api/src/middleware/getMember.js
@@ -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(new DatabaseError(err))
+ })
+ } catch (error) {
+ reject(new DatabaseError(error))
+ }
+ })
+}
+
+export default getUser
diff --git a/api/src/auth/middleware/jwt.js b/api/src/middleware/jwt.js
similarity index 100%
rename from api/src/auth/middleware/jwt.js
rename to api/src/middleware/jwt.js
diff --git a/client/src/graphql/teams/DeleteTeamMutation.js b/client/src/graphql/teams/DeleteTeamMutation.js
index 0db2a7ad4..ce02bc213 100644
--- a/client/src/graphql/teams/DeleteTeamMutation.js
+++ b/client/src/graphql/teams/DeleteTeamMutation.js
@@ -2,8 +2,8 @@
import gql from 'graphql-tag'
export const DELETE_TEAM = gql`
- mutation deleteTeam($slug: String!) {
- teams_DeleteTeam(slug: $slug) {
+ mutation deleteTeam($slug: String!, $botSlug: String!) {
+ teams_DeleteTeam(slug: $slug, botSlug: $botSlug) {
id
}
}
diff --git a/client/src/graphql/teams/GetTeamsByOwnerQuery.js b/client/src/graphql/teams/GetTeamsByOwnerQuery.js
index adbb28c4a..730769d8b 100644
--- a/client/src/graphql/teams/GetTeamsByOwnerQuery.js
+++ b/client/src/graphql/teams/GetTeamsByOwnerQuery.js
@@ -2,8 +2,8 @@
import gql from 'graphql-tag'
export const GET_TEAMS_BY_OWNER = gql`
- query teamsByOwnerQuery($authId: String!) {
- teams_TeamsByOwner(ownerId: $authId) {
+ query teamsByOwnerQuery {
+ teams_TeamsByOwner {
id
name
slug
diff --git a/client/src/utils/graphql-errors.js b/client/src/utils/graphql-errors.js
index 26b9c18ce..8ada52b66 100644
--- a/client/src/utils/graphql-errors.js
+++ b/client/src/utils/graphql-errors.js
@@ -1,12 +1,14 @@
+import log from './log'
+
const ErrorResponse = {
'unique constraint': 'Sorry, already taken! Please create a unique '
}
export const checkGraphQLError = error => {
- console.log('checkGraphQLError ', ErrorResponse)
+ log.debug('checkGraphQLError ', ErrorResponse)
if (error.search(/unique constraint/)) {
const field = error.substring(error.indexOf('=') + 1)
- console.log('unique constraint', field.replace(/ +/g, ''))
+ log.debug('unique constraint', field.replace(/ +/g, ''))
}
}
diff --git a/client/src/utils/log.js b/client/src/utils/log.js
new file mode 100644
index 000000000..47e819934
--- /dev/null
+++ b/client/src/utils/log.js
@@ -0,0 +1,7 @@
+import minilog from 'minilog'
+
+if (process.env.NODE_ENV === 'development') minilog.enable()
+
+const log = minilog('frontend')
+
+export default log
diff --git a/client/src/views/common/components/TeamBar.js b/client/src/views/common/components/TeamBar.js
index b51f22e13..324fc3d13 100644
--- a/client/src/views/common/components/TeamBar.js
+++ b/client/src/views/common/components/TeamBar.js
@@ -13,9 +13,12 @@ import UsersIcon from '@material-ui/icons/People'
import SearchIcon from '@material-ui/icons/Search'
import AdbIcon from '@material-ui/icons/Adb'
import SettingsApplicationsIcon from '@material-ui/icons/SettingsApplications'
+import BugReportIcon from '@material-ui/icons/BugReport'
import { Link } from 'react-router-dom'
+import log from '../../../utils/log'
+
const SettingsLink = props =>
const FBLink = props =>
const MembersLink = props =>
@@ -61,13 +64,13 @@ const styles = theme => ({
class TeamBar extends Component {
render () {
const { classes, user, match } = this.props
- console.log('TeamBar: ', user, match)
+ log.debug('TeamBar: ', user, match)
return (
-
+
- Manage Teams
+ Teams
+
diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js
index 1dfb75850..5e655ccf1 100644
--- a/client/src/views/dashboard/components/CreateTeam.js
+++ b/client/src/views/dashboard/components/CreateTeam.js
@@ -10,9 +10,11 @@ import { checkGraphQLError } from '../../../utils/graphql-errors'
import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
+import log from '../../../utils/log'
+
const CreateTeam = ({ authId }) => {
let input
- console.log('CreateTeam', authId)
+ log.debug('CreateTeam', authId)
return (
{
if (error) {
errors = error.graphQLErrors.map(({ message }, i) => {
const displayMessage = checkGraphQLError(message)
- console.log('createTeam error:', displayMessage)
+ log.debug('createTeam error:', displayMessage)
return (
{message}
@@ -73,7 +75,7 @@ const handleSubmit = async (e, createTeam, input) => {
const currentUser = await getItem('user')
let authId = JSON.parse(currentUser)
authId = authId.authId
- console.log('createTeam submit: ', authId)
+ log.debug('createTeam submit: ', authId)
const name = input.value
const slug = slugify(name)
await createTeam({ variables: { name, slug, owner: authId } })
diff --git a/client/src/views/dashboard/components/CreateTeamDialog.js b/client/src/views/dashboard/components/CreateTeamDialog.js
index 6da04291b..6c9ce0113 100644
--- a/client/src/views/dashboard/components/CreateTeamDialog.js
+++ b/client/src/views/dashboard/components/CreateTeamDialog.js
@@ -18,7 +18,7 @@ import { isEmpty } from '../../../utils/js-helpers'
import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
-// import { checkGraphQLError } from '../../../utils/graphql-errors'
+import log from '../../../utils/log'
const styles = theme => ({
dialogContainer: {
@@ -207,7 +207,7 @@ export class CreateTeamDialog extends Component {
async handleSubmit (e, createTeam, name, botName) {
e.preventDefault()
- console.log('createTeam submit: ', name, botName)
+ log.debug('createTeam submit: ', name, botName)
const slug = this.slugify(name)
const botSlug = this.slugify(botName)
await createTeam({ variables: { name, slug, botName, botSlug } })
diff --git a/client/src/views/dashboard/components/CreateTeamForm.js b/client/src/views/dashboard/components/CreateTeamForm.js
index 75df97b5d..ebdbaf358 100644
--- a/client/src/views/dashboard/components/CreateTeamForm.js
+++ b/client/src/views/dashboard/components/CreateTeamForm.js
@@ -11,6 +11,8 @@ import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import Typography from '@material-ui/core/Typography'
+import log from '../../../utils/log'
+
export class CreateTeamDialog extends Component {
constructor (props) {
super(props)
@@ -50,7 +52,7 @@ export class CreateTeamDialog extends Component {
}
render () {
- console.log(this.props)
+ log.debug(this.props)
return (
@@ -50,8 +52,7 @@ export const ManageTeamsItem = ({ classes, team, authId, ...props }) => {
ManageTeamsItem.propTypes = {
classes: PropTypes.object.isRequired,
- team: PropTypes.object.isRequired,
- authId: PropTypes.string.isRequired
+ team: PropTypes.object.isRequired
}
export default ManageTeamsItem
diff --git a/client/src/views/manage-teams/components/ManageTeamsList.js b/client/src/views/manage-teams/components/ManageTeamsList.js
index 0fdf78fae..59577baa6 100644
--- a/client/src/views/manage-teams/components/ManageTeamsList.js
+++ b/client/src/views/manage-teams/components/ManageTeamsList.js
@@ -1,20 +1,18 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Query } from 'react-apollo'
-import { withStateHandlers, lifecycle, compose } from 'recompose'
import Grid from '@material-ui/core/Grid'
import { MessageCard } from '@advancedalgos/web-components'
import { withStyles } from '@material-ui/core/styles'
-import { isDefined, isString } from '../../../utils/js-helpers'
-import { getItem } from '../../../utils/local-storage'
-
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import ManageTeamsItem from './ManageTeamsItem'
import CreateTeamDialog from './CreateTeamDialog'
+import log from '../../../utils/log'
+
const styles = theme => ({
heroContent: {
maxWidth: 600,
@@ -47,105 +45,66 @@ const styles = theme => ({
}
})
-export const ManageTeamsList = ({ classes, user = null, ...props }) => {
- let owner
- let authId = null
- console.log('ManageTeamsList: ', user)
- if (user !== null && isString(user)) {
- owner = JSON.parse(user)
- if (isDefined(owner.authId)) authId = owner.authId
- }
- console.log('ManageTeamsList 2: ', owner, authId)
- if (authId === undefined || authId === null) {
- return (
-
-
-
-
-
- )
- } else {
- return (
-
- {({ loading, error, data }) => {
- console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
+export const ManageTeamsList = ({ classes, user = null, ...props }) => (
+
+ {({ loading, error, data }) => {
+ log.debug('GET_TEAMS_BY_OWNER: ', loading, error, data)
- let errors = null
- if (error) {
- errors = error.graphQLErrors.map(({ message }, i) => {
- return
- })
- }
- if (!loading && !error) {
- if (data.teams_TeamsByOwner.length > 0) {
- return (
-
-
- {!loading &&
- data.teams_TeamsByOwner.map(team => (
-
- ))}
- {errors}
-
-
- )
- } else {
- return (
-
-
-
-
-
-
-
- )
- }
- } else {
- return (
+ let errors = null
+ if (error) {
+ errors = error.graphQLErrors.map(({ message }, i) => {
+ return
+ })
+ }
+ if (!loading && !error) {
+ if (data.teams_TeamsByOwner.length > 0) {
+ return (
+
-
-
- {errors !== null && }
-
+ {!loading &&
+ data.teams_TeamsByOwner.map(team => (
+
+ ))}
+ {errors}
- )
- }
- }}
-
- )
- }
-}
+
+ )
+ } else {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+ } else {
+ return (
+
+
+
+ {errors !== null && }
+
+
+ )
+ }
+ }}
+
+)
ManageTeamsList.propTypes = {
user: PropTypes.any,
classes: PropTypes.object.isRequired
}
-const getUserOnMount = lifecycle({
- componentDidMount () {
- getItem('user').then(user => {
- this.setState({ user })
- }) // Set user to state
- }
-})
-
-const mapStateToProps = withStateHandlers(() => ({ user: null }), {
- user: ({ user }) => () => ({ user })
-})
-
-const ManageTeamsListAuthId = compose(
- mapStateToProps,
- getUserOnMount
-)(ManageTeamsList)
-
-export default withStyles(styles)(ManageTeamsListAuthId)
+export default withStyles(styles)(ManageTeamsList)
diff --git a/client/src/views/team-members/components/ManageMemberDelete.js b/client/src/views/team-members/components/ManageMemberDelete.js
index cc75e3df1..e7e731703 100644
--- a/client/src/views/team-members/components/ManageMemberDelete.js
+++ b/client/src/views/team-members/components/ManageMemberDelete.js
@@ -15,6 +15,7 @@ import REMOVE_TEAM_MEMBER from '../../../graphql/teams/RemoveTeamMemberMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import { checkGraphQLError } from '../../../utils/graphql-errors'
+import log from '../../../utils/log'
const styles = theme => ({
dialogContainer: {
@@ -54,7 +55,7 @@ export class ManageMemberDelete extends Component {
}
render () {
- console.log(this.props, this.props.teamId)
+ log.debug(this.props, this.props.teamId)
const { classes, teamId, authId } = this.props
return (
{
const displayMessage = checkGraphQLError(message)
- console.log('createTeam error:', displayMessage)
+ log.debug('createTeam error:', displayMessage)
return (
{message}
diff --git a/client/src/views/team-members/components/ManageMemberRole.js b/client/src/views/team-members/components/ManageMemberRole.js
index f428ebbb6..08823d3b7 100644
--- a/client/src/views/team-members/components/ManageMemberRole.js
+++ b/client/src/views/team-members/components/ManageMemberRole.js
@@ -17,6 +17,7 @@ import SET_TEAM_MEMBER_ROLE from '../../../graphql/teams/SetTeamMemberRoleMutati
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import { checkGraphQLError } from '../../../utils/graphql-errors'
+import log from '../../../utils/log'
const styles = theme => ({
dialogContainer: {
@@ -62,7 +63,7 @@ export class ManageMemberRole extends Component {
}
render () {
- console.log(this.props, this.props.teamId)
+ log.debug(this.props, this.props.teamId)
const { classes, teamId, authId } = this.props
return (
{
const displayMessage = checkGraphQLError(message)
- console.log('createTeam error:', displayMessage)
+ log.debug('createTeam error:', displayMessage)
return (
{message}
diff --git a/client/src/views/team-members/components/ManageMemberStatus.js b/client/src/views/team-members/components/ManageMemberStatus.js
index fba5880ee..b5267f098 100644
--- a/client/src/views/team-members/components/ManageMemberStatus.js
+++ b/client/src/views/team-members/components/ManageMemberStatus.js
@@ -10,6 +10,8 @@ import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardActions from '@material-ui/core/CardActions'
+import log from '../../../utils/log'
+
const styles = theme => ({
dialogContainer: {
display: 'block',
@@ -47,7 +49,7 @@ export class ManageMemberStatus extends Component {
}
render () {
- console.log(this.props, this.props.status)
+ log.debug(this.props, this.props.status)
const { classes, status } = this.props
return (
diff --git a/client/src/views/team-members/components/ManageMembersItem.js b/client/src/views/team-members/components/ManageMembersItem.js
index daad67f3e..3dd2be7fb 100644
--- a/client/src/views/team-members/components/ManageMembersItem.js
+++ b/client/src/views/team-members/components/ManageMembersItem.js
@@ -9,8 +9,10 @@ import ManageMemberRole from './ManageMemberRole'
import ManageMemberStatus from './ManageMemberStatus'
import { MessageCard } from '@advancedalgos/web-components'
+import log from '../../../utils/log'
+
export const ManageMembersItem = ({ classes, member, teamId, authId }) => {
- console.log('ManageMembersItem', member)
+ log.debug('ManageMembersItem', member)
let profile = null
let email = null
let memberStatus = null
diff --git a/client/src/views/team-members/components/ManageMembersTeamItem.js b/client/src/views/team-members/components/ManageMembersTeamItem.js
index f8bdbf102..186576377 100644
--- a/client/src/views/team-members/components/ManageMembersTeamItem.js
+++ b/client/src/views/team-members/components/ManageMembersTeamItem.js
@@ -12,6 +12,8 @@ import InviteMemberDialog from './InviteMemberDialog'
import ManageMembersItem from './ManageMembersItem'
import { MessageCard } from '@advancedalgos/web-components'
+import log from '../../../utils/log'
+
const styles = theme => ({
heroContent: {
maxWidth: 600,
@@ -56,7 +58,7 @@ const styles = theme => ({
})
export const ManageMembersTeamItem = ({ classes, team, authId }) => {
- console.log('ManageMembersItem', team, team.profile, team.profile.avatar)
+ log.debug('ManageMembersItem', team, team.profile, team.profile.avatar)
let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
avatar = team.profile.avatar
diff --git a/client/src/views/teams/AcceptTeamInvite.js b/client/src/views/teams/AcceptTeamInvite.js
index 1dde43cf4..58fa28efa 100644
--- a/client/src/views/teams/AcceptTeamInvite.js
+++ b/client/src/views/teams/AcceptTeamInvite.js
@@ -2,6 +2,7 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { parse } from '../../utils/js-helpers'
+import log from '../../utils/log'
import { MessageCard } from '@advancedalgos/web-components'
@@ -9,7 +10,7 @@ class AcceptTeamInvite extends Component {
render () {
const { location, auth } = this.props
const param = parse(location.search)
- console.log(param, auth)
+ log.debug(param, auth)
if (auth === undefined) {
return
diff --git a/client/src/views/teams/components/TeamsList.js b/client/src/views/teams/components/TeamsList.js
index a8bd4cf84..ac416122f 100644
--- a/client/src/views/teams/components/TeamsList.js
+++ b/client/src/views/teams/components/TeamsList.js
@@ -10,6 +10,7 @@ import { MessageCard } from '@advancedalgos/web-components'
import GET_ALL_TEAMS_QUERY from '../../../graphql/teams/GetAllTeamsQuery'
import { isEmpty } from '../../../utils/js-helpers'
+import log from '../../../utils/log'
import TeamsItem from './TeamsItem'
import TeamsDetails from './TeamsDetails'
@@ -42,7 +43,7 @@ const styles = theme => ({
export const TeamsList = ({ classes, match }) => (
{({ loading, error, data, ...props }) => {
- console.log('GET_ALL_TEAMS: ', loading, error, data, match, props)
+ log.debug('GET_ALL_TEAMS: ', loading, error, data, match, props)
let slug = null
if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug
diff --git a/client/tools/log.js b/client/tools/log.js
deleted file mode 100644
index 978d6d4bb..000000000
--- a/client/tools/log.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import minilog from 'minilog'
-
-minilog.enable()
-
-const log = minilog('frontend')
-
-let consoleLog = global.console.log
-
-global.console.log = function () {
- consoleLog.apply(global.console, arguments)
-}
-
-export default log