diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..78575d67f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [Unreleased] +### Changed +- [List changes here for upcoming release] + +## 0.1.0 - 2018-12-14 +### Added +- Notifications Module - Sending notifications such as emails, messages to client, etc +- Reintroduced CORS whitelist +- Created CHANGELOG — for the logging of changes + +### Removed +- Removed Sendgrid Mutations (moved to notifications module) + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/package.json b/package.json index e2b128d1f..f32897886 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "master-app", - "version": "0.0.1", + "version": "0.1.0", "description": "Responsible for loading all web modules and running them.", "main": "index.js", "scripts": { diff --git a/server/.env.example b/server/.env.example index ddb7185f4..7a98bc3d7 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,13 +1,24 @@ +NODE_ENV=development + TEAMS_API_PRESHARED=THIS_IS_VERY_SECRET USERS_API_PRESHARED=THIS_IS_VERY_SECRET EVENTS_API_PRESHARED=THIS_IS_VERY_SECRET KEYVAULT_API_PRESHARED=THIS_IS_VERY_SECRET +FINANCIAL_BEINGS_API_PRESHARED=THIS_IS_VERY_SECRET +NOTIFICATIONS_API_PRESHARED=THIS_IS_VERY_SECRET -GRAPHQL_API_URL=https://app-api.advancedalgos.net/graphql -TEAMS_API_URL=https://teams-api.advancedalgos.net/graphql -USERS_API_URL=https://users-api.advancedalgos.net/graphql -EVENTS_API_URL=https://events-api.advancedalgos.net/graphql -KEYVAULT_API_URL=https://keyvault-api.advancedalgos.net/graphql +# PROJECT_SITE_URL=https://advancedalgos.net +PROJECT_SITE_URL=http://localhost:3999 +# PLATFORM_URL=https://platform.advancedalgos.net +PLATFORM_URL=http://localhost:3100 + +GRAPHQL_API_URL=https://platform-api-dev.advancedalgos.net/graphql +TEAMS_API_URL=https://teams-api-dev.advancedalgos.net/graphql +USERS_API_URL=https://users-api-dev.advancedalgos.net/graphql +EVENTS_API_URL=https://events-api-dev.advancedalgos.net/graphql +KEYVAULT_API_URL=https://keyvault-api-dev.advancedalgos.net/graphql +FINANCIAL_BEINGS_API_URL=https://financialbeings-api-dev.advancedalgos.net/graphql +NOTIFICATIONS_API_URL=https://notifications-api-dev.advancedalgos.net/graphql AUTH0_DOMAIN=auth0-domain AUTH0_AUDIENCE=auth0-audience @@ -16,8 +27,3 @@ AUTH0_ISSUER=auth0-issuer AACLOUD_ID=aacloud-id RECAPTCHA= - -SG_APIKEY= -SG_APIKEY_CONTACTS= -SG_SIGNUP_EMAILID= -SG_CONTACT_EMAILID= diff --git a/server/src/index.js b/server/src/index.js index 75ebfebc0..845a5fd30 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -9,8 +9,7 @@ import axios from 'axios' import { createTransformedRemoteSchema } from './createRemoteSchema' import { teams, events } from './links' -import { typeDef as masterSchema } from './schema' -import masterResolvers from './resolvers' + import logger from './logger' async function getUserId (authId) { @@ -68,11 +67,15 @@ async function run () { 'financialBeings_', process.env.FINANCIAL_BEINGS_API_URL, process.env.FINANCIAL_BEINGS_API_PRESHARED) - logger.info('FINANCIAL_BEINGS schema created') + logger.info('Financial Beings schema created') + const transformedNotificationsSchema = await createTransformedRemoteSchema( + 'notifications_', + process.env.NOTIFICATIONS_API_URL, + process.env.NOTIFICATIONS_API_PRESHARED) + logger.info('Notifications schema created') - var schemas = [masterSchema] + var schemas = [] var resolvers = {} - resolvers = Object.assign(resolvers, masterResolvers) if (transformedTeamsSchema) { schemas.push(transformedTeamsSchema) @@ -97,7 +100,10 @@ async function run () { if (transformedFinancialBeingsSchema) { schemas.push(transformedFinancialBeingsSchema) } - + if (transformedNotificationsSchema) { + schemas.push(transformedNotificationsSchema) + } + const schema = mergeSchemas({ schemas, resolvers @@ -164,7 +170,7 @@ async function run () { return error }, formatResponse: response => { - logger.debug('Response from Apolo Server: ' + response) + logger.debug('Response from Apollo Server: ' + response) return response }, playground: { @@ -175,9 +181,29 @@ async function run () { } }) - server.applyMiddleware({ app }) + const whitelist = [ + process.env.PROJECT_SITE_URL, + process.env.PLATFORM_URL, + process.env.GRAPHQL_API_URL, + process.env.TEAMS_API_URL, + process.env.USERS_API_URL, + process.env.EVENTS_API_URL, + process.env.KEYVAULT_API_URL, + process.env.FINANCIAL_BEINGS_API_URL, + process.env.NOTIFICATIONS_API_URL + ] - app.use(cors()) + const corsOptionsDelegate = (req, callback) => { + let corsOptions + if (whitelist.indexOf(req.header('Origin')) !== -1) { + corsOptions = { origin: true, credentials: true } + } else { + corsOptions = { origin: false, credentials: true } + } + callback(null, corsOptions) + } + + server.applyMiddleware({ app, cors: corsOptionsDelegate }) app.listen(4100) logger.info(`Server running. Open ${process.env.GRAPHQL_API_URL} to run queries.`) diff --git a/server/src/resolvers/index.js b/server/src/resolvers/index.js index c260c10b3..9919da6d3 100644 --- a/server/src/resolvers/index.js +++ b/server/src/resolvers/index.js @@ -1,9 +1,9 @@ import merge from 'lodash.merge' -import { SendgridMutations } from './mutation' +// import { SendgridMutations } from './mutation' const resolvers = { Mutation: { - ...SendgridMutations + // ...SendgridMutations } } diff --git a/server/src/resolvers/mutation/index.js b/server/src/resolvers/mutation/index.js index 70ad9aef6..e69de29bb 100644 --- a/server/src/resolvers/mutation/index.js +++ b/server/src/resolvers/mutation/index.js @@ -1,3 +0,0 @@ -import SendgridMutations from './sendgrid' - -export { SendgridMutations } diff --git a/server/src/resolvers/mutation/sendgrid.js b/server/src/resolvers/mutation/sendgrid.js deleted file mode 100644 index 40b9c1275..000000000 --- a/server/src/resolvers/mutation/sendgrid.js +++ /dev/null @@ -1,237 +0,0 @@ -import axios from 'axios' -import jwt from 'jsonwebtoken' -import { ApolloError } from 'apollo-server-express' - -import logger from '../../logger' - -const API_KEY = process.env.SG_APIKEY -const API_KEY_CONTACTS = process.env.SG_APIKEY_CONTACTS -let origin = process.env.SANDGRID_ORIGN - -export default { - async master_NewsletterSignup(parent, { email }, ctx, info) { - logger.info('master_NewsletterSignup params email:') - logger.info(email) - const token = jwt.sign({ email: email }, API_KEY, { expiresIn: '1d' }) - const params = '/email-verification?token=' - - 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: { - "aaverifylink": origin + params + token, - "subject": 'VERIFY YOUR INTEREST in Advanced Algos' - }, - "subject": 'VERIFY YOUR INTEREST in Advanced Algos' - } - ], - "from": { - "email": "feedback@advancedalgos.net", - "name": "Advanced Algos Team" - }, - "reply_to": { - "email": "feedback@advancedalgos.net", - "name": "Advanced Algos Team" - }, - "template_id": process.env.SG_SIGNUP_EMAILID - }) - - const 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) { - logger.info('Sendgrid sendVerify response:') - logger.info(response) - if (response.status >= 200 && response.status < 300) { - return 'SUCCESS' - } else { - throw response.data.errors[0].message - } - }) - .catch(function (error) { - logger.error('Sendgrid sendVerify Error:') - logger.error(error) - throw new ApolloError(`Sendgrid sendVerify Error: ${error.response.data.errors[0].message}`, 404) - }) - return sendVerify - }, - async master_NewsletterSignupVerify(parent, { token }, ctx, info){ - let origin = process.env.SANDGRID_ORIGN - const headers = { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin' : origin, - 'Access-Control-Allow-Credentials': 'true' - } - - let verifiedToken - try { - verifiedToken = jwt.verify(token, API_KEY, {maxAge: '1d'}) - } catch(err) { - logger.error('Sendgrid verifiedToken Error:') - logger.error(err) - if (err.name === 'TokenExpiredError'){ - throw new ApolloError('Error: Token Expired. Please resubmit email address.', 400) - } else { - throw new ApolloError(`Error: ${err.message}`, 400) - } - } - logger.info('Sendgrid verifySignup verifiedToken: ') - logger.info(verifiedToken) - - const email = verifiedToken.email - - const subscribe = axios({ - method: 'post', - url: 'https://api.sendgrid.com/v3/contactdb/recipients', - data: [{"email": email}], - headers:{ - 'content-type': 'application/json', - 'authorization': 'Bearer ' + API_KEY_CONTACTS - } - }) - .then(response => { - logger.info('Sendgrid verifySignup subscribe: ') - logger.info(response) - const recipients = response.data.persisted_recipients - - if (recipients.length > 0 ){ - const addToList = axios({ - method: 'post', - url: 'https://api.sendgrid.com/v3/contactdb/lists/4068018/recipients/' + recipients[0], - headers:{ - 'content-type': 'application/json', - 'authorization': 'Bearer ' + API_KEY_CONTACTS - } - }) - .then(response => { - logger.info('Sendgrid verifySignup addToList: ') - logger.info(response) - if (response.status >= 200 && response.status < 300) { - return 'SUCCESS' - } else { - throw response.data.errors[0].message - } - }) - .catch(error => { - logger.error('Sendgrid verifySignUp subscribe Error:') - logger.error(error) - throw `Email SignUp Error: ${error}` - }) - return addToList - } else{ - return response.data.errors[0].message - } - }) - .then(response => { - return response - }) - .catch(error => { - logger.error('Sendgrid verifySubscribe Error:') - logger.error(error) - throw new ApolloError(`Sendgrid verifySubscribe Error: ${error.response.data.errors[0].message}`, 404) - }) - return subscribe - }, - async master_Contact(parent, { email, subject, message, recaptcha }, ctx, info) { - const headers = { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin' : origin, - 'Access-Control-Allow-Credentials': 'true' - } - - const toEmail = 'feedback@advancedalgos.net' - - const data = JSON.stringify({ - "personalizations": [ - { - "to": [ - { - "email": email - } - ], - dynamic_template_data: { - "aacontactname": name, - "aacontactemail": email, - "aacontactbody": message - }, - "subject": `AA Corporate Site Contact - Message from ${name}` - } - ], - "from": { - "email": email, - "name": name - }, - "reply_to": { - "email": email, - "name": name - }, - "template_id": process.env.SG_CONTACT_EMAILID - }) - - const checkCaptcha = axios({ - method: 'post', - url: 'https://www.google.com/recaptcha/api/siteverify', - params: { - secret: process.env.RECAPTCHA, - response: recaptcha - } - }) - .then(function (response) { - logger.info(response.data) - if (response.status >= 200 && response.status < 300 && response.data.success) { - context.log('presend SendGrid') - return 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) { - logger.info('Sendgrid Contact response: ') - logger.info(response) - if (response.status >= 200 && response.status < 300) { - return `Contact email sent` - } else { - throw response.data.errors[0].message - } - }) - .catch(function (error) { - logger.error(`sendgrid Error: ${JSON.stringify(error)}`) - throw `Contact email send error: ${error.response.data.errors[0].message}` - }) - }else{ - throw response.data - } - }) - .then(function(response){ - return response - }) - .catch(function (error) { - logger.error('Sendgrid Contact RECAPTCHA Error:') - logger.error(error) - throw new ApolloError(`Sendgrid Contact RECAPTCHA Error: ${error.response.data.errors[0].message}`, 404) - }) - - return checkCaptcha - } -} diff --git a/server/src/schema/index.js b/server/src/schema/index.js index 4b416cceb..8b1651b1d 100644 --- a/server/src/schema/index.js +++ b/server/src/schema/index.js @@ -1,8 +1,6 @@ export const typeDef = ` type Mutation { - master_NewsletterSignup(email: String!): String - master_NewsletterSignupVerify(token: String!): String - master_Contact(email: String!, subject: String!, Message: String!, recaptcha: String!): String + master_SampleMutation(variable: String!): String } schema {