Merge pull request #95 from keen-studio/src-directory-restructure

refactor directory structure
This commit is contained in:
Dan Ribbens
2019-10-03 15:48:35 -04:00
committed by GitHub
42 changed files with 414 additions and 415 deletions

View File

@@ -1,6 +1,7 @@
import validate from 'express-validation';
import Joi from 'joi';
// TODO: move field specific validations to the config
export default {
post: validate({
body: {

View File

@@ -1,54 +1,54 @@
export default {
port: 3000,
serverUrl: "http://localhost:3000",
cors: ['http://localhost:8080', 'http://localhost:8081'],
adminURL: "/payload-login",
serverUrl: 'http://localhost:3000',
cors: ['http://localhost', 'http://localhost:8080', 'http://localhost:8081'],
adminURL: '/payload-login',
routes: {
api: "/api",
admin: "/admin"
api: '/api',
admin: '/admin'
},
mongoURL: "mongodb://localhost/payload",
mongoURL: 'mongodb://localhost/payload',
roles: [
"admin",
"editor",
"moderator",
"user",
"viewer"
'admin',
'editor',
'moderator',
'user',
'viewer'
],
localization: {
locales: [
"en",
"es"
'en',
'es'
],
defaultLocale: "en",
defaultLocale: 'en',
fallback: true
},
staticUrl: "/media",
staticDir: "demo/media",
staticUrl: '/media',
staticDir: 'demo/media',
imageSizes: [
{
name: "tablet",
name: 'tablet',
width: 640,
height: 480,
crop: "left top"
crop: 'left top'
},
{
name: "mobile",
name: 'mobile',
width: 320,
height: 240,
crop: "left top"
crop: 'left top'
},
{
name: "icon",
name: 'icon',
width: 16,
height: 16
}
],
email: {
provider: "mock"
provider: 'mock'
},
graphQL: {
path: "/graphql",
path: '/graphql',
graphiql: true
}
};

View File

@@ -3,7 +3,7 @@
* @param roles
* @returns {Function}
*/
export default function checkRole(...roles) {
export default function checkRoleMiddleware(...roles) {
return function (req, res, next) {
if (!roles.some(role => role === req.user.role)) res.status(401).send('Role not authorized.');
else next();

View File

@@ -1,7 +1,7 @@
import jwt from 'jsonwebtoken';
import passport from 'passport';
import httpStatus from 'http-status';
import APIError from '../lib/helpers/APIError';
import APIError from '../errors/APIError';
export default User => ({
/**

View File

@@ -1,34 +1,34 @@
const httpStatus = require('http-status');
/**
* @extends Error
*/
class ExtendableError extends Error {
constructor(message, status, isPublic) {
super(message);
this.name = this.constructor.name;
this.message = message;
this.status = status;
this.isPublic = isPublic;
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
Error.captureStackTrace(this, this.constructor.name);
}
}
/**
* Class representing an API error.
* @extends ExtendableError
*/
class APIError extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) {
super(message, status, isPublic);
}
}
module.exports = APIError;
const httpStatus = require('http-status');
/**
* @extends Error
*/
class ExtendableError extends Error {
constructor(message, status, isPublic) {
super(message);
this.name = this.constructor.name;
this.message = message;
this.status = status;
this.isPublic = isPublic;
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
Error.captureStackTrace(this, this.constructor.name);
}
}
/**
* Class representing an API error.
* @extends ExtendableError
*/
class APIError extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) {
super(message, status, isPublic);
}
}
module.exports = APIError;

View File

@@ -5,20 +5,22 @@ import bodyParser from 'body-parser';
import methodOverride from 'method-override';
import jwtStrategy from './auth/jwt';
import fileUpload from 'express-fileupload';
import mediaRoutes from './routes/media.routes';
import mediaRoutes from './media/media.routes';
import emailRoutes from './auth/passwordResets/email.routes';
import autopopulate from './plugins/autopopulate';
import paginate from './plugins/paginate';
import buildQuery from './plugins/buildQuery';
import internationalization from './plugins/internationalization';
import { bindModel, locale, checkRole } from './middleware';
import { query, create, findOne, destroy, update } from './requestHandlers';
import { schemaBaseFields } from './helpers/mongoose/schemaBaseFields';
import fieldToSchemaMap from './helpers/mongoose/fieldToSchemaMap';
import autopopulate from './mongoose/autopopulate.plugin';
import paginate from './mongoose/paginate.plugin';
import buildQueryPlugin from './mongoose/buildQuery.plugin';
import localizationPlugin from './localization/localization.plugin';
import bindModelMiddleware from './mongoose/bindModel.middleware';
import localizationMiddleware from './localization/localization.middleware';
import checkRoleMiddleware from './auth/checkRole.middleware';
import { query, create, findOne, destroy, update } from './mongoose/requestHandlers';
import { schemaBaseFields } from './mongoose/schemaBaseFields';
import fieldToSchemaMap from './mongoose/fieldToSchemaMap';
import authValidate from './auth/validate';
import authRequestHandlers from './auth/requestHandlers';
import passwordResetConfig from './auth/passwordResets/passwordReset.config';
import validateConfig from './lib/validateConfig';
import validateConfig from './utilities/validateConfig';
class Payload {
@@ -62,7 +64,7 @@ class Payload {
options.app.use(methodOverride('X-HTTP-Method-Override'));
options.app.use(express.urlencoded({ extended: true }));
options.app.use(bodyParser.urlencoded({ extended: true }));
options.app.use(locale(options.config.localization));
options.app.use(localizationMiddleware(options.config.localization));
options.app.use(options.router);
// TODO: Build safe config before initializing models and routes
@@ -84,8 +86,8 @@ class Payload {
const Schema = new mongoose.Schema(fields, { timestamps: config.timestamps });
Schema.plugin(paginate);
Schema.plugin(buildQuery);
Schema.plugin(internationalization, options.config.localization);
Schema.plugin(buildQueryPlugin);
Schema.plugin(localizationPlugin, options.config.localization);
Schema.plugin(autopopulate);
if (config.plugins) {
@@ -117,7 +119,7 @@ class Payload {
options.config.roles.forEach((role) => {
options.router
.route(`/role/${role}`)
.get(passport.authenticate(config.auth.strategy, { session: false }), checkRole(role), auth.me);
.get(passport.authenticate(config.auth.strategy, { session: false }), checkRoleMiddleware(role), auth.me);
});
// password resets
@@ -133,7 +135,7 @@ class Payload {
}
this.models[config.labels.singular] = model;
options.router.all(`/${config.slug}*`, bindModel(model));
options.router.all(`/${config.slug}*`, bindModelMiddleware(model));
options.router.route(`/${config.slug}`)
.get(config.policies.read, query)

View File

@@ -6,7 +6,7 @@ import languageParser from 'accept-language-parser';
* @param localization
* @returns {Function}
*/
export default function locale(localization) {
export default function localizationMiddleware(localization) {
return function (req, res, next) {
let setLocale;
if (req.query.locale) {

View File

@@ -1,6 +1,6 @@
import mongoose from 'mongoose';
export default function internationalization(schema, options) {
export default function localizationPlugin(schema, options) {
if (!options || !options.locales || !Array.isArray(options.locales) || !options.locales.length) {
throw new mongoose.Error('Required locales array is missing');
}
@@ -21,7 +21,7 @@ export default function internationalization(schema, options) {
schema.eachPath((path, schemaType) => {
if (schemaType.schema) { // propagate plugin initialization for sub-documents schemas
schemaType.schema.plugin(internationalization, pluginOptions);
schemaType.schema.plugin(localizationPlugin, pluginOptions);
return;
}

View File

@@ -1,7 +1,7 @@
import mongoose from 'mongoose';
import buildQuery from '../plugins/buildQuery';
import paginate from '../plugins/paginate';
import internationalization from '../plugins/internationalization';
import buildQueryPlugin from '../mongoose/buildQuery.plugin';
import paginate from '../mongoose/paginate.plugin';
import localizationPlugin from '../localization/localization.plugin';
const mediaModelLoader = (config) => {
const MediaSchema = new mongoose.Schema({
@@ -19,8 +19,8 @@ const mediaModelLoader = (config) => {
);
MediaSchema.plugin(paginate);
MediaSchema.plugin(buildQuery);
MediaSchema.plugin(internationalization, config.localization);
MediaSchema.plugin(buildQueryPlugin);
MediaSchema.plugin(localizationPlugin, config.localization);
return mongoose.model('Media', MediaSchema);
};

View File

@@ -1,34 +1,34 @@
import sharp from 'sharp';
const { promisify } = require('util');
const sizeOf = promisify(require('image-size'));
function getOutputImageName(sourceImage, size) {
let extension = sourceImage.split('.').pop();
let filenameWithoutExtension = sourceImage.substr(0, sourceImage.lastIndexOf('.')) || sourceImage;
return `${filenameWithoutExtension}-${size.width}x${size.height}.${extension}`;
}
export async function resizeAndSave(config, file) {
let sourceImage = `${config.staticDir}/${file.name}`;
let outputSizes = [];
try {
const dimensions = await sizeOf(sourceImage);
for (let desiredSize of config.imageSizes) {
if (desiredSize.width > dimensions.width) {
continue;
}
let outputImageName = getOutputImageName(sourceImage, desiredSize);
await sharp(sourceImage)
.resize(desiredSize.width, desiredSize.height, {
position: desiredSize.crop || 'centre'
})
.toFile(outputImageName);
outputSizes.push({ height: desiredSize.height, width: desiredSize.width });
}
} catch (e) {
console.log('error in resize and save', e.message);
}
return outputSizes;
}
import sharp from 'sharp';
const { promisify } = require('util');
const sizeOf = promisify(require('image-size'));
function getOutputImageName(sourceImage, size) {
let extension = sourceImage.split('.').pop();
let filenameWithoutExtension = sourceImage.substr(0, sourceImage.lastIndexOf('.')) || sourceImage;
return `${filenameWithoutExtension}-${size.width}x${size.height}.${extension}`;
}
export async function resizeAndSave(config, file) {
let sourceImage = `${config.staticDir}/${file.name}`;
let outputSizes = [];
try {
const dimensions = await sizeOf(sourceImage);
for (let desiredSize of config.imageSizes) {
if (desiredSize.width > dimensions.width) {
continue;
}
let outputImageName = getOutputImageName(sourceImage, desiredSize);
await sharp(sourceImage)
.resize(desiredSize.width, desiredSize.height, {
position: desiredSize.crop || 'centre'
})
.toFile(outputImageName);
outputSizes.push({ height: desiredSize.height, width: desiredSize.width });
}
} catch (e) {
console.log('error in resize and save', e.message);
}
return outputSizes;
}

View File

@@ -1,7 +1,7 @@
import mkdirp from 'mkdirp';
import { resizeAndSave } from '../utils/imageResizer';
import { resizeAndSave } from './imageResizer';
import httpStatus from 'http-status';
import modelById from '../resolvers/modelById';
import modelById from '../mongoose/resolvers/modelById';
export async function update(req, res, next, config) {
req.model.setDefaultLocale(req.locale);

View File

@@ -1,15 +1,15 @@
import express from 'express';
import passport from 'passport';
import { upload, update } from '../controllers/media.controller';
import { query } from '../requestHandlers';
import bindModel from '../middleware/bindModel';
import mediaModelLoader from '../models/Media.model';
import { upload, update } from './media.controller';
import { query } from '../mongoose/requestHandlers';
import bindModelMiddleware from '../mongoose/bindModel.middleware';
import mediaModelLoader from './Media.model';
const router = express.Router();
const mediaRoutes = config => {
const mediaModel = mediaModelLoader(config); // Needs config for intl
router.all('*', bindModel(mediaModel));
router.all('*', bindModelMiddleware(mediaModel));
router
.route('')

View File

@@ -1,5 +0,0 @@
import bindModel from './bindModel';
import checkRole from './checkRole';
import locale from './locale';
export { bindModel, checkRole, locale };

View File

@@ -1,153 +1,153 @@
'use strict';
const mongoose = require('mongoose');
module.exports = function (schema) {
const pathsToPopulate = [];
eachPathRecursive(schema, (pathname, schemaType) => {
let option;
if (schemaType.options && schemaType.options.autopopulate) {
option = schemaType.options.autopopulate;
pathsToPopulate.push({
options: defaultOptions(pathname, schemaType.options),
autopopulate: option
});
} else if (schemaType.options &&
schemaType.options.type &&
schemaType.options.type[0] &&
schemaType.options.type[0].autopopulate) {
option = schemaType.options.type[0].autopopulate;
pathsToPopulate.push({
options: defaultOptions(pathname, schemaType.options.type[0]),
autopopulate: option
});
}
});
if (schema.virtuals) {
Object.keys(schema.virtuals).forEach((pathname) => {
if (schema.virtuals[pathname].options.autopopulate) {
pathsToPopulate.push({
options: defaultOptions(pathname, schema.virtuals[pathname].options),
autopopulate: schema.virtuals[pathname].options.autopopulate,
});
}
});
}
var autopopulateHandler = function () {
if (this._mongooseOptions &&
this._mongooseOptions.lean &&
// If lean and user didn't explicitly do `lean({ autopulate: true })`,
// skip it. See gh-27, gh-14, gh-48
!this._mongooseOptions.lean.autopopulate) {
return;
}
const options = this.options || {};
if (options.autopopulate === false) {
return;
}
let maxDepth = options.maxDepth;
if (options.autopopulate && options.autopopulate.maxDepth) {
maxDepth = options.autopopulate.maxDepth;
}
const depth = options._depth != null ? options._depth : 0;
if (options.maxDepth > 0 && depth >= maxDepth) {
return;
}
const numPaths = pathsToPopulate.length;
for (let i = 0; i < numPaths; ++i) {
pathsToPopulate[i].options = pathsToPopulate[i].options || {};
pathsToPopulate[i].options.options = pathsToPopulate[i].options.options || {};
Object.assign(pathsToPopulate[i].options.options, {
...options,
_depth: depth + 1
});
processOption.call(this,
pathsToPopulate[i].autopopulate, pathsToPopulate[i].options);
}
};
schema.
pre('find', autopopulateHandler).
pre('findOne', autopopulateHandler).
pre('findOneAndUpdate', autopopulateHandler);
};
function defaultOptions(pathname, v) {
const ret = { path: pathname, options: { maxDepth: 10 } };
if (v.ref != null) {
ret.model = v.ref;
ret.ref = v.ref;
}
if (v.refPath != null) {
ret.refPath = v.refPath;
}
return ret;
}
function processOption(value, options) {
switch (typeof value) {
case 'function':
handleFunction.call(this, value, options);
break;
case 'object':
handleObject.call(this, value, options);
break;
default:
handlePrimitive.call(this, value, options);
break;
}
}
function handlePrimitive(value, options) {
if (value) {
this.populate(options);
}
}
function handleObject(value, optionsToUse) {
// Special case: support top-level `maxDepth`
if (value.maxDepth != null) {
optionsToUse.options = optionsToUse.options || {};
optionsToUse.options.maxDepth = value.maxDepth;
delete value.maxDepth;
}
optionsToUse = Object.assign({}, optionsToUse, value);
this.populate(optionsToUse);
}
function handleFunction(fn, options) {
const val = fn.call(this, options);
processOption.call(this, val, options);
}
function mergeOptions(destination, source) {
const keys = Object.keys(source);
const numKeys = keys.length;
for (let i = 0; i < numKeys; ++i) {
destination[keys[i]] = source[keys[i]];
}
}
function eachPathRecursive(schema, handler, path) {
if (!path) {
path = [];
}
schema.eachPath((pathname, schemaType) => {
path.push(pathname);
if (schemaType.schema) {
eachPathRecursive(schemaType.schema, handler, path);
} else {
handler(path.join('.'), schemaType);
}
path.pop();
});
}
'use strict';
const mongoose = require('mongoose');
module.exports = function (schema) {
const pathsToPopulate = [];
eachPathRecursive(schema, (pathname, schemaType) => {
let option;
if (schemaType.options && schemaType.options.autopopulate) {
option = schemaType.options.autopopulate;
pathsToPopulate.push({
options: defaultOptions(pathname, schemaType.options),
autopopulate: option
});
} else if (schemaType.options &&
schemaType.options.type &&
schemaType.options.type[0] &&
schemaType.options.type[0].autopopulate) {
option = schemaType.options.type[0].autopopulate;
pathsToPopulate.push({
options: defaultOptions(pathname, schemaType.options.type[0]),
autopopulate: option
});
}
});
if (schema.virtuals) {
Object.keys(schema.virtuals).forEach((pathname) => {
if (schema.virtuals[pathname].options.autopopulate) {
pathsToPopulate.push({
options: defaultOptions(pathname, schema.virtuals[pathname].options),
autopopulate: schema.virtuals[pathname].options.autopopulate,
});
}
});
}
var autopopulateHandler = function () {
if (this._mongooseOptions &&
this._mongooseOptions.lean &&
// If lean and user didn't explicitly do `lean({ autopulate: true })`,
// skip it. See gh-27, gh-14, gh-48
!this._mongooseOptions.lean.autopopulate) {
return;
}
const options = this.options || {};
if (options.autopopulate === false) {
return;
}
let maxDepth = options.maxDepth;
if (options.autopopulate && options.autopopulate.maxDepth) {
maxDepth = options.autopopulate.maxDepth;
}
const depth = options._depth != null ? options._depth : 0;
if (options.maxDepth > 0 && depth >= maxDepth) {
return;
}
const numPaths = pathsToPopulate.length;
for (let i = 0; i < numPaths; ++i) {
pathsToPopulate[i].options = pathsToPopulate[i].options || {};
pathsToPopulate[i].options.options = pathsToPopulate[i].options.options || {};
Object.assign(pathsToPopulate[i].options.options, {
...options,
_depth: depth + 1
});
processOption.call(this,
pathsToPopulate[i].autopopulate, pathsToPopulate[i].options);
}
};
schema.
pre('find', autopopulateHandler).
pre('findOne', autopopulateHandler).
pre('findOneAndUpdate', autopopulateHandler);
};
function defaultOptions(pathname, v) {
const ret = { path: pathname, options: { maxDepth: 10 } };
if (v.ref != null) {
ret.model = v.ref;
ret.ref = v.ref;
}
if (v.refPath != null) {
ret.refPath = v.refPath;
}
return ret;
}
function processOption(value, options) {
switch (typeof value) {
case 'function':
handleFunction.call(this, value, options);
break;
case 'object':
handleObject.call(this, value, options);
break;
default:
handlePrimitive.call(this, value, options);
break;
}
}
function handlePrimitive(value, options) {
if (value) {
this.populate(options);
}
}
function handleObject(value, optionsToUse) {
// Special case: support top-level `maxDepth`
if (value.maxDepth != null) {
optionsToUse.options = optionsToUse.options || {};
optionsToUse.options.maxDepth = value.maxDepth;
delete value.maxDepth;
}
optionsToUse = Object.assign({}, optionsToUse, value);
this.populate(optionsToUse);
}
function handleFunction(fn, options) {
const val = fn.call(this, options);
processOption.call(this, val, options);
}
function mergeOptions(destination, source) {
const keys = Object.keys(source);
const numKeys = keys.length;
for (let i = 0; i < numKeys; ++i) {
destination[keys[i]] = source[keys[i]];
}
}
function eachPathRecursive(schema, handler, path) {
if (!path) {
path = [];
}
schema.eachPath((pathname, schemaType) => {
path.push(pathname);
if (schemaType.schema) {
eachPathRecursive(schemaType.schema, handler, path);
} else {
handler(path.join('.'), schemaType);
}
path.pop();
});
}

View File

@@ -1,8 +1,8 @@
const bindModel = model => {
const bindModelMiddleware = model => {
return (req, res, next) => {
req.model = model;
next();
};
};
export default bindModel;
export default bindModelMiddleware;

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-use-before-define */
export default function buildQuery(schema) {
export default function buildQueryPlugin(schema) {
schema.statics.apiQuery = function (rawParams, locale, cb) {
const model = this;

View File

@@ -1,4 +1,4 @@
import { createAutopopulateOptions } from '../helpers/mongoose/createAutopopulateOptions';
import { createAutopopulateOptions } from './createAutopopulateOptions';
/**
* @param {Object} [dbQuery={}]
@@ -19,9 +19,9 @@ import { createAutopopulateOptions } from '../helpers/mongoose/createAutopopulat
* @returns {Promise}
*/
function paginate(dbQuery, options, callback) {
function paginatePlugin(dbQuery, options, callback) {
dbQuery = dbQuery || {};
options = Object.assign({}, paginate.options, options);
options = Object.assign({}, paginatePlugin.options, options);
options.customLabels = options.customLabels ? options.customLabels : {};
let defaultLimit = 10;
@@ -150,7 +150,7 @@ function paginate(dbQuery, options, callback) {
* @param {Schema} schema
*/
module.exports = function (schema) {
schema.statics.paginate = paginate;
schema.statics.paginate = paginatePlugin;
};
module.exports.paginate = paginate;
module.exports.paginate = paginatePlugin;

View File

@@ -1,17 +1,17 @@
import httpStatus from 'http-status';
const create = (req, res) => {
req.model.setDefaultLocale(req.locale); // TODO - move to middleware
req.model.create(req.body, (err, result) => {
if (err)
return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: err });
return res.status(httpStatus.CREATED)
.json({
message: 'success',
result: result.toJSON({ virtuals: true })
});
});
};
export default create;
import httpStatus from 'http-status';
const create = (req, res) => {
req.model.setDefaultLocale(req.locale); // TODO - move to middleware
req.model.create(req.body, (err, result) => {
if (err)
return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: err });
return res.status(httpStatus.CREATED)
.json({
message: 'success',
result: result.toJSON({ virtuals: true })
});
});
};
export default create;

View File

@@ -1,6 +1,6 @@
import httpStatus from 'http-status';
import { modelById } from '../resolvers';
import { createAutopopulateOptions } from '../helpers/mongoose/createAutopopulateOptions';
import { createAutopopulateOptions } from '../createAutopopulateOptions';
const findOne = (req, res) => {

View File

@@ -2,7 +2,7 @@
const create = query => {
return new Promise((resolve, reject) => {
query.Model.create(query.input, (err, doc) => {
console.log(err,doc);
console.log(err, doc);
if (err || !doc) {
return reject({message: err})
}

View File

@@ -1,23 +1,23 @@
const find = query => {
return new Promise((resolve, reject) => {
query.Model.find({}, (err, docs) => {
// if (err || !doc) {
// return reject({ message: 'not found' })
// }
let result = docs;
if (query.locale) {
docs.setLocale(query.locale, query.fallback);
const json = docs.toJSON({ virtuals: true });
result = json;
}
resolve(result);
})
})
};
export default find;
const find = query => {
return new Promise((resolve, reject) => {
query.Model.find({}, (err, docs) => {
// if (err || !doc) {
// return reject({ message: 'not found' })
// }
let result = docs;
if (query.locale) {
docs.setLocale(query.locale, query.fallback);
const json = docs.toJSON({ virtuals: true });
result = json;
}
resolve(result);
})
})
};
export default find;

View File

@@ -1,9 +1,9 @@
import modelById from './modelById';
import find from './find';
import create from './create';
export {
modelById,
find,
create
}
import modelById from './modelById';
import find from './find';
import create from './create';
export {
modelById,
find,
create
}

View File

@@ -1,24 +1,24 @@
const modelById = (query, options) => {
return new Promise((resolve, reject) => {
query.Model.findOne({ _id: query.id }, {}, options, (err, doc) => {
if (err || !doc) {
return reject({ message: 'not found' })
}
let result = doc;
if (query.locale) {
doc.setLocale(query.locale, query.fallback);
result = doc.toJSON({ virtuals: true });
}
resolve(options.returnRawDoc
? doc
: result);
})
})
};
export default modelById;
const modelById = (query, options) => {
return new Promise((resolve, reject) => {
query.Model.findOne({ _id: query.id }, {}, options, (err, doc) => {
if (err || !doc) {
return reject({ message: 'not found' })
}
let result = doc;
if (query.locale) {
doc.setLocale(query.locale, query.fallback);
result = doc.toJSON({ virtuals: true });
}
resolve(options.returnRawDoc
? doc
: result);
})
})
};
export default modelById;

View File

@@ -1,4 +1,5 @@
import { checkRole, locale} from '../../middleware';
import localizationMiddleware from '../../localization/localization.middleware';
import checkRoleMiddleware from '../../auth/checkRole.middleware';
import mockExpress from 'jest-mock-express';
let res = null;
@@ -18,7 +19,7 @@ describe('Payload Middleware', () => {
}
};
checkRole('user')(req, res, next);
checkRoleMiddleware('user')(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(res.status).not.toHaveBeenCalled();
@@ -31,7 +32,7 @@ describe('Payload Middleware', () => {
}
};
checkRole('admin')(req, res, next);
checkRoleMiddleware('admin')(req, res, next);
expect(next).not.toHaveBeenCalled();
expect(res.status).toHaveBeenCalled();
@@ -45,7 +46,7 @@ describe('Payload Middleware', () => {
}
};
checkRole('admin', 'user')(req, res, next);
checkRoleMiddleware('admin', 'user')(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(res.status).not.toHaveBeenCalled();
@@ -58,7 +59,7 @@ describe('Payload Middleware', () => {
}
};
checkRole('admin', 'owner')(req, res, next);
checkRoleMiddleware('admin', 'owner')(req, res, next);
expect(next).not.toHaveBeenCalled();
expect(res.status).toHaveBeenCalled();
@@ -87,7 +88,7 @@ describe('Payload Middleware', () => {
it('Supports query params', () => {
req.query.locale = 'es';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual(req.query.locale);
@@ -96,7 +97,7 @@ describe('Payload Middleware', () => {
it('Supports query param fallback to default', () => {
req.query.locale = 'pt';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual(localization.defaultLocale);
@@ -105,7 +106,7 @@ describe('Payload Middleware', () => {
it('Supports accept-language header', () => {
req.headers['accept-language'] = 'es,fr;';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual('es');
@@ -115,7 +116,7 @@ describe('Payload Middleware', () => {
req.query.locale = 'pt';
req.headers['accept-language'] = 'fr;';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual(localization.defaultLocale);
@@ -125,14 +126,14 @@ describe('Payload Middleware', () => {
req.query.locale = 'es';
req.headers['accept-language'] = 'en;';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual('es');
});
it('Supports default locale', () => {
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual(localization.defaultLocale);
@@ -140,7 +141,7 @@ describe('Payload Middleware', () => {
it('Supports locale all', () => {
req.query.locale = '*';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toBeUndefined();
@@ -149,7 +150,7 @@ describe('Payload Middleware', () => {
it('Supports locale in body on post', () => {
req.body = {locale: 'es'};
req.method = 'post';
locale(localization)(req, res, next);
localizationMiddleware(localization)(req, res, next);
expect(next).toHaveBeenCalledTimes(1);
expect(req.locale).toEqual('es');

View File

@@ -1,6 +1,6 @@
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import mongooseApiQuery from '../../plugins/buildQuery';
import mongooseApiQuery from '../../mongoose/buildQuery.plugin';
const TestUserSchema = new Schema({
name: {type: String},

View File

@@ -3,7 +3,7 @@ import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import { intlModel } from './testModels/IntlModel';
import { paramParser } from '../../plugins/buildQuery';
import { paramParser } from '../../mongoose/buildQuery.plugin';
const AuthorSchema = new Schema({
name: String,

View File

@@ -1,8 +1,8 @@
import mongoose from 'mongoose';
import { schemaBaseFields } from '../../../helpers/mongoose/schemaBaseFields';
import paginate from '../../../plugins/paginate';
import buildQuery from '../../../plugins/buildQuery';
import internationalization from '../../../plugins/internationalization';
import { schemaBaseFields } from '../../../mongoose/schemaBaseFields';
import paginate from '../../../mongoose/paginate.plugin';
import buildQueryPlugin from '../../../mongoose/buildQuery.plugin';
import localizationPlugin from '../../../localization/localization.plugin';
const IntlSchema = new mongoose.Schema({
...schemaBaseFields,
@@ -15,8 +15,8 @@ const IntlSchema = new mongoose.Schema({
);
IntlSchema.plugin(paginate);
IntlSchema.plugin(buildQuery);
IntlSchema.plugin(internationalization, {
IntlSchema.plugin(buildQueryPlugin);
IntlSchema.plugin(localizationPlugin, {
locales: [
'en',
'es'

View File

@@ -1,22 +1,22 @@
export const convertArrayToObject = (arr, key) => {
return arr.reduce((obj, item) => {
if (key) {
obj[item[key]] = item;
return obj;
}
obj[item] = {};
return obj;
}, {});
}
export const convertObjectToArray = arr => {
return Object.values(arr);
}
export const convertArrayToHash = (arr, key) => {
return arr.reduce((obj, item, i) => {
obj[item[key]] = i;
return obj;
}, {});
}
export const convertArrayToObject = (arr, key) => {
return arr.reduce((obj, item) => {
if (key) {
obj[item[key]] = item;
return obj;
}
obj[item] = {};
return obj;
}, {});
}
export const convertObjectToArray = arr => {
return Object.values(arr);
}
export const convertArrayToHash = (arr, key) => {
return arr.reduce((obj, item, i) => {
obj[item[key]] = i;
return obj;
}, {});
}

View File

@@ -1 +1 @@
export default (keys, obj) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
export default (keys, obj) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});

View File

@@ -1,3 +1,3 @@
const toKebabCase = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
export default toKebabCase;
const toKebabCase = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
export default toKebabCase;

View File

@@ -1,4 +1,4 @@
import { DuplicateModelNameError } from './errors/DuplicateModelNameError';
import { DuplicateModelNameError } from '../errors/DuplicateModelNameError';
export default function validateConfig(config, models) {
if (models[config.labels.singular]) {

View File

@@ -1,3 +1,3 @@
export { default as toKebabCase } from './lib/helpers/toKebabCase';
export { default as getPropSubset } from './lib/helpers/getPropSubset';
export { convertArrayToHash, convertArrayToObject, convertObjectToArray } from './lib/helpers/convertData';
export { default as toKebabCase } from './helpers/toKebabCase';
export { default as getPropSubset } from './helpers/getPropSubset';
export { convertArrayToHash, convertArrayToObject, convertObjectToArray } from './helpers/convertData';