Skip to content

Commit

Permalink
complete API
Browse files Browse the repository at this point in the history
  • Loading branch information
webdevstar committed Oct 22, 2018
1 parent a3427cf commit 222c8f6
Show file tree
Hide file tree
Showing 69 changed files with 10,762 additions and 0 deletions.
Binary file added src/api/server/.DS_Store
Binary file not shown.
73 changes: 73 additions & 0 deletions src/api/server/lib/dashboardWebSocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import WebSocket from 'ws';
import url from 'url';
import security from './security';

let wss = null;

const listen = server => {
wss = new WebSocket.Server({
path: '/ws/dashboard', //Accept only connections matching this path
maxPayload: 1024, //The maximum allowed message size
backlog: 100, //The maximum length of the queue of pending connections.
verifyClient: verifyClient, //An hook to reject connections
server //A pre-created HTTP/S server to use
});

wss.on('connection', onConnection);
wss.broadcast = broadcastToAll;
};

const getTokenFromRequestPath = requestPath => {
try {
const urlObj = url.parse(requestPath, true);
return urlObj.query.token;
} catch (e) {
return null;
}
};

const verifyClient = (info, done) => {
if (security.DEVELOPER_MODE === true) {
done(true);
} else {
const requestPath = info.req.url;
const token = getTokenFromRequestPath(requestPath);
security
.verifyToken(token)
.then(tokenDecoded => {
// TODO: check access to dashboard
done(true);
})
.catch(err => {
done(false, 401);
});
}
};

const onConnection = (ws, req) => {
// TODO: ws.user = token.email
ws.on('error', () => {});
};

const broadcastToAll = data => {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(data, error => {});
}
});
};

const send = ({ event, payload }) => {
wss.broadcast(JSON.stringify({ event, payload }));
};

const events = {
ORDER_CREATED: 'order.created',
THEME_INSTALLED: 'theme.installed'
};

export default {
listen: listen,
send: send,
events: events
};
46 changes: 46 additions & 0 deletions src/api/server/lib/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import winston from 'winston';
const LOGS_FILE = 'logs/server.log';

winston.configure({
transports: [
new winston.transports.Console({
level: 'debug',
handleExceptions: true,
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}),
new winston.transports.File({
level: 'info',
handleExceptions: true,
format: winston.format.json(),
filename: LOGS_FILE
})
]
});

const getResponse = message => ({
error: true,
message
});

const logUnauthorizedRequests = req => {
// todo
};

const sendResponse = (err, req, res, next) => {
if (err && err.name === 'UnauthorizedError') {
logUnauthorizedRequests(req);
res.status(401).send(getResponse(err.message));
} else if (err) {
winston.error(err.stack);
res.status(500).send(getResponse(err.message));
} else {
next();
}
};

export default {
sendResponse
};
80 changes: 80 additions & 0 deletions src/api/server/lib/mailer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import winston from 'winston';
import nodemailer from 'nodemailer';
import smtpTransport from 'nodemailer-smtp-transport';
import settings from './settings';
import EmailSettingsService from '../services/settings/email';

const SMTP_FROM_CONFIG_FILE = {
host: settings.smtpServer.host,
port: settings.smtpServer.port,
secure: settings.smtpServer.secure,
auth: {
user: settings.smtpServer.user,
pass: settings.smtpServer.pass
}
};

const getSmtpFromEmailSettings = emailSettings => {
return {
host: emailSettings.host,
port: emailSettings.port,
secure: emailSettings.port === 465,
auth: {
user: emailSettings.user,
pass: emailSettings.pass
}
};
};

const getSmtp = emailSettings => {
const useSmtpServerFromConfigFile = emailSettings.host === '';
const smtp = useSmtpServerFromConfigFile
? SMTP_FROM_CONFIG_FILE
: getSmtpFromEmailSettings(emailSettings);

return smtp;
};

const sendMail = (smtp, message) => {
return new Promise((resolve, reject) => {
if (!message.to.includes('@')) {
reject('Invalid email address');
return;
}

const transporter = nodemailer.createTransport(smtpTransport(smtp));
transporter.sendMail(message, (err, info) => {
if (err) {
reject(err);
} else {
resolve(info);
}
});
});
};

const getFrom = emailSettings => {
const useSmtpServerFromConfigFile = emailSettings.host === '';
return useSmtpServerFromConfigFile
? `"${settings.smtpServer.fromName}" <${settings.smtpServer.fromAddress}>`
: `"${emailSettings.from_name}" <${emailSettings.from_address}>`;
};

const send = async message => {
const emailSettings = await EmailSettingsService.getEmailSettings();
const smtp = getSmtp(emailSettings);
message.from = getFrom(emailSettings);

try {
const result = await sendMail(smtp, message);
winston.info('Email sent', result);
return true;
} catch (e) {
winston.error('Email send failed', e);
return false;
}
};

export default {
send: send
};
48 changes: 48 additions & 0 deletions src/api/server/lib/mongo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import winston from 'winston';
import url from 'url';
import { MongoClient } from 'mongodb';
import settings from './settings';

const mongodbConnection = settings.mongodbServerUrl;
const mongoPathName = url.parse(mongodbConnection).pathname;
const dbName = mongoPathName.substring(mongoPathName.lastIndexOf('/') + 1);

const RECONNECT_INTERVAL = 1000;
const CONNECT_OPTIONS = {
reconnectTries: 3600,
reconnectInterval: RECONNECT_INTERVAL,
useNewUrlParser: true
};

const onClose = () => {
winston.info('MongoDB connection was closed');
};

const onReconnect = () => {
winston.info('MongoDB reconnected');
};

export let db = null;

const connectWithRetry = () => {
MongoClient.connect(
mongodbConnection,
CONNECT_OPTIONS,
(err, client) => {
if (err) {
winston.error(
`MongoDB connection was failed: ${err.message}`,
err.message
);
setTimeout(connectWithRetry, RECONNECT_INTERVAL);
} else {
db = client.db(dbName);
db.on('close', onClose);
db.on('reconnect', onReconnect);
winston.info('MongoDB connected successfully');
}
}
);
};

connectWithRetry();
147 changes: 147 additions & 0 deletions src/api/server/lib/parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { ObjectID } from 'mongodb';

const getString = value => (value || '').toString();

const getDateIfValid = value => {
const date = Date.parse(value);
return isNaN(date) ? null : new Date(date);
};

const getArrayIfValid = value => {
return Array.isArray(value) ? value : null;
};

const getArrayOfObjectID = value => {
if (Array.isArray(value) && value.length > 0) {
return value.map(id => getObjectIDIfValid(id)).filter(id => !!id);
} else {
return [];
}
};

const isNumber = value => !isNaN(parseFloat(value)) && isFinite(value);

const getNumberIfValid = value => (isNumber(value) ? parseFloat(value) : null);

const getNumberIfPositive = value => {
const n = getNumberIfValid(value);
return n && n >= 0 ? n : null;
};

const getBooleanIfValid = (value, defaultValue = null) => {
if (value === 'true' || value === 'false') {
return value === 'true';
} else {
return typeof value === 'boolean' ? value : defaultValue;
}
};

const getObjectIDIfValid = value => {
return ObjectID.isValid(value) ? new ObjectID(value) : null;
};

const getBrowser = browser => {
return browser
? {
ip: getString(browser.ip),
user_agent: getString(browser.user_agent)
}
: {
ip: '',
user_agent: ''
};
};

const getCustomerAddress = address => {
let coordinates = {
latitude: '',
longitude: ''
};

if (address && address.coordinates) {
coordinates.latitude = address.coordinates.latitude;
coordinates.longitude = address.coordinates.longitude;
}

return address
? {
id: new ObjectID(),
address1: getString(address.address1),
address2: getString(address.address2),
city: getString(address.city),
country: getString(address.country).toUpperCase(),
state: getString(address.state),
phone: getString(address.phone),
postal_code: getString(address.postal_code),
full_name: getString(address.full_name),
company: getString(address.company),
tax_number: getString(address.tax_number),
coordinates: coordinates,
details: address.details,
default_billing: false,
default_shipping: false
}
: {};
};

const getOrderAddress = address => {
let coordinates = {
latitude: '',
longitude: ''
};

if (address && address.coordinates) {
coordinates.latitude = address.coordinates.latitude;
coordinates.longitude = address.coordinates.longitude;
}

const emptyAddress = {
address1: '',
address2: '',
city: '',
country: '',
state: '',
phone: '',
postal_code: '',
full_name: '',
company: '',
tax_number: '',
coordinates: coordinates,
details: null
};

return address
? Object.assign(
{},
{
address1: getString(address.address1),
address2: getString(address.address2),
city: getString(address.city),
country: getString(address.country).toUpperCase(),
state: getString(address.state),
phone: getString(address.phone),
postal_code: getString(address.postal_code),
full_name: getString(address.full_name),
company: getString(address.company),
tax_number: getString(address.tax_number),
coordinates: coordinates,
details: address.details
},
address
)
: emptyAddress;
};

export default {
getString: getString,
getObjectIDIfValid: getObjectIDIfValid,
getDateIfValid: getDateIfValid,
getArrayIfValid: getArrayIfValid,
getArrayOfObjectID: getArrayOfObjectID,
getNumberIfValid: getNumberIfValid,
getNumberIfPositive: getNumberIfPositive,
getBooleanIfValid: getBooleanIfValid,
getBrowser: getBrowser,
getCustomerAddress: getCustomerAddress,
getOrderAddress: getOrderAddress
};
Loading

0 comments on commit 222c8f6

Please sign in to comment.