From 49ebdaa1ec62aee2e4d21306bd1ea3aa0020bc03 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 1 Apr 2020 15:21:31 -0400 Subject: [PATCH] binds all API routes to api prefix route, refactors to support --- src/auth/init.js | 20 --- src/auth/register.js | 31 +++++ src/auth/routes.js | 11 ++ src/bin/build.js | 2 +- src/client/components/Routes.js | 2 +- src/client/components/data/User.js | 2 +- .../forms/field-types/Relationship/index.js | 2 +- src/client/components/layout/Sidebar/index.js | 2 +- .../components/modals/StayLoggedIn/index.js | 2 +- .../components/modules/Localizer/index.js | 2 +- .../modules/SearchableTable/index.js | 2 +- .../components/modules/UploadMedia/index.js | 2 +- .../components/utilities/Locale/index.js | 2 +- .../utilities/RedirectToLogin/index.js | 2 +- .../components/views/CreateFirstUser/index.js | 2 +- .../components/views/Dashboard/index.js | 2 +- src/client/components/views/Login/index.js | 2 +- src/client/components/views/Logout/index.js | 2 +- src/client/components/views/NotFound/index.js | 2 +- .../views/collections/Edit/index.js | 2 +- .../views/collections/List/index.js | 2 +- .../components/views/globals/Edit/index.js | 2 +- src/client/config/index.js | 3 - ...itizedClientConfig.js => securedConfig.js} | 4 +- src/collections/register.js | 19 +++ .../{registerRoutes.js => routes.js} | 7 +- src/express/middleware.js | 35 ++++++ src/globals/bindGlobalMiddleware.js | 8 -- .../{registerSchema.js => buildSchema.js} | 8 +- src/globals/middleware.js | 8 ++ src/globals/register.js | 12 ++ src/globals/{registerRoutes.js => routes.js} | 15 ++- src/index.js | 119 +++++------------- src/init/cors.js | 18 --- src/init/passport.js | 8 -- src/init/registerExpressMiddleware.js | 17 --- src/init/uploads.js | 8 -- .../connect.js} | 0 src/routes/init.js | 19 --- src/uploads/register.js | 35 ++++++ src/uploads/routes.js | 5 +- .../config => webpack}/getStyleLoaders.js | 0 .../config => webpack}/getWebpackDevConfig.js | 15 ++- .../getWebpackProdConfig.js | 0 src/{init/webpack.js => webpack/init.js} | 19 +-- 45 files changed, 244 insertions(+), 238 deletions(-) delete mode 100644 src/auth/init.js create mode 100644 src/auth/register.js delete mode 100644 src/client/config/index.js rename src/client/{config/sanitizedClientConfig.js => securedConfig.js} (63%) create mode 100644 src/collections/register.js rename src/collections/{registerRoutes.js => routes.js} (86%) create mode 100644 src/express/middleware.js delete mode 100644 src/globals/bindGlobalMiddleware.js rename src/globals/{registerSchema.js => buildSchema.js} (83%) create mode 100644 src/globals/middleware.js create mode 100644 src/globals/register.js rename src/globals/{registerRoutes.js => routes.js} (65%) delete mode 100644 src/init/cors.js delete mode 100644 src/init/passport.js delete mode 100644 src/init/registerExpressMiddleware.js delete mode 100644 src/init/uploads.js rename src/{init/connectMongoose.js => mongoose/connect.js} (100%) delete mode 100644 src/routes/init.js create mode 100644 src/uploads/register.js rename src/{client/config => webpack}/getStyleLoaders.js (100%) rename src/{client/config => webpack}/getWebpackDevConfig.js (87%) rename src/{client/config => webpack}/getWebpackProdConfig.js (100%) rename src/{init/webpack.js => webpack/init.js} (55%) diff --git a/src/auth/init.js b/src/auth/init.js deleted file mode 100644 index fc0336512b..0000000000 --- a/src/auth/init.js +++ /dev/null @@ -1,20 +0,0 @@ -const passport = require('passport'); -const AnonymousStrategy = require('passport-anonymous'); -const jwtStrategy = require('./jwt'); -const initRoutes = require('../routes/init'); -const authRoutes = require('./routes'); - -const initUserAuth = (User, config, router) => { - passport.use(User.createStrategy()); - - passport.use(jwtStrategy(User, config)); - passport.serializeUser(User.serializeUser()); - passport.deserializeUser(User.deserializeUser()); - - passport.use(new AnonymousStrategy.Strategy()); - - router.use('', initRoutes(User)); - router.use('', authRoutes(config, User)); -}; - -module.exports = initUserAuth; diff --git a/src/auth/register.js b/src/auth/register.js new file mode 100644 index 0000000000..5118ed189f --- /dev/null +++ b/src/auth/register.js @@ -0,0 +1,31 @@ +const mongoose = require('mongoose'); +const passport = require('passport'); +const AnonymousStrategy = require('passport-anonymous'); +const passportLocalMongoose = require('passport-local-mongoose'); +const jwtStrategy = require('./jwt'); +const authRoutes = require('./routes'); +const buildCollectionSchema = require('../collections/buildSchema'); +const baseUserFields = require('../auth/baseFields'); +const collectionRoutes = require('../collections/routes'); + +function registerUser() { + this.config.user.fields.push(...baseUserFields); + const userSchema = buildCollectionSchema(this.config.user, this.config); + userSchema.plugin(passportLocalMongoose, { usernameField: this.config.user.auth.useAsUsername }); + this.User = mongoose.model(this.config.user.labels.singular, userSchema); + + passport.use(this.User.createStrategy()); + passport.use(jwtStrategy(this.User, this.config)); + passport.serializeUser(this.User.serializeUser()); + passport.deserializeUser(this.User.deserializeUser()); + passport.use(new AnonymousStrategy.Strategy()); + + this.router.use(authRoutes(this.config, this.User)); + + this.router.use(collectionRoutes({ + model: this.User, + config: this.config.user, + })); +} + +module.exports = registerUser; diff --git a/src/auth/routes.js b/src/auth/routes.js index 8d6bce9ca7..5dcfb0c16a 100644 --- a/src/auth/routes.js +++ b/src/auth/routes.js @@ -8,6 +8,17 @@ const router = express.Router(); const authRoutes = (config, User) => { const auth = authRequestHandlers(config, User); + router + .route('/init') + .get((req, res) => { + User.countDocuments({}, (err, count) => { + if (err) res.status(200).json({ error: err }); + return count >= 1 + ? res.status(200).json({ initialized: true }) + : res.status(200).json({ initialized: false }); + }); + }); + router .route('/login') .post(auth.login); diff --git a/src/bin/build.js b/src/bin/build.js index bfc7d97f5a..46fe3fb80b 100644 --- a/src/bin/build.js +++ b/src/bin/build.js @@ -3,7 +3,7 @@ const path = require('path'); const webpack = require('webpack'); -const getWebpackProdConfig = require('../client/config/getWebpackProdConfig'); +const getWebpackProdConfig = require('../webpack/getWebpackProdConfig'); module.exports = (args) => { const configPath = path.resolve(process.cwd(), (args.config || './payload.config.js')); diff --git a/src/client/components/Routes.js b/src/client/components/Routes.js index d1f8c1bfe2..d66a6b6041 100644 --- a/src/client/components/Routes.js +++ b/src/client/components/Routes.js @@ -3,7 +3,7 @@ import { Route, Switch, withRouter, Redirect, } from 'react-router-dom'; import DefaultList from './views/collections/List'; -import config from '../config/sanitizedClientConfig'; +import config from '../securedConfig'; import { useUser } from './data/User'; import Dashboard from './views/Dashboard'; import Login from './views/Login'; diff --git a/src/client/components/data/User.js b/src/client/components/data/User.js index 7ff2362bbd..bad644fb78 100644 --- a/src/client/components/data/User.js +++ b/src/client/components/data/User.js @@ -7,7 +7,7 @@ import PropTypes from 'prop-types'; import Cookies from 'universal-cookie'; import { useModal } from '@trbl/react-modal'; import { requests } from '../../api'; -import config from '../../config/sanitizedClientConfig'; +import config from '../../securedConfig'; import StayLoggedInModal from '../modals/StayLoggedIn'; import useThrottledEffect from '../../hooks/useThrottledEffect'; diff --git a/src/client/components/forms/field-types/Relationship/index.js b/src/client/components/forms/field-types/Relationship/index.js index 20b38d5e33..4036d4475b 100644 --- a/src/client/components/forms/field-types/Relationship/index.js +++ b/src/client/components/forms/field-types/Relationship/index.js @@ -4,7 +4,7 @@ import Cookies from 'universal-cookie'; import some from 'async-some'; import ReactSelect from '../../../modules/ReactSelect'; import useFieldType from '../../useFieldType'; -import config from '../../../../config/sanitizedClientConfig'; +import config from '../../../../securedConfig'; import Label from '../../Label'; import Error from '../../Error'; diff --git a/src/client/components/layout/Sidebar/index.js b/src/client/components/layout/Sidebar/index.js index 58e1839cf9..a1a3393268 100644 --- a/src/client/components/layout/Sidebar/index.js +++ b/src/client/components/layout/Sidebar/index.js @@ -1,6 +1,6 @@ import React from 'react'; import { useLocation, NavLink, Link } from 'react-router-dom'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import Arrow from '../../graphics/Arrow'; import Icon from '../../graphics/Icon'; diff --git a/src/client/components/modals/StayLoggedIn/index.js b/src/client/components/modals/StayLoggedIn/index.js index 0f47674a50..f5dd2e828d 100644 --- a/src/client/components/modals/StayLoggedIn/index.js +++ b/src/client/components/modals/StayLoggedIn/index.js @@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom'; import { asModal } from '@trbl/react-modal'; import ContentBlock from '../../layout/ContentBlock'; import Button from '../../controls/Button'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import './index.scss'; diff --git a/src/client/components/modules/Localizer/index.js b/src/client/components/modules/Localizer/index.js index d16618f5dd..f8be1cc95a 100644 --- a/src/client/components/modules/Localizer/index.js +++ b/src/client/components/modules/Localizer/index.js @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { Link } from 'react-router-dom'; import qs from 'qs'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import { useLocale } from '../../utilities/Locale'; import { useSearchParams } from '../../utilities/SearchParams'; import Arrow from '../../graphics/Arrow'; diff --git a/src/client/components/modules/SearchableTable/index.js b/src/client/components/modules/SearchableTable/index.js index 3340017945..2630e56b55 100644 --- a/src/client/components/modules/SearchableTable/index.js +++ b/src/client/components/modules/SearchableTable/index.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import Filter from '../Filter'; import Table from '../../layout/Table'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; const { routes: { admin } } = config; diff --git a/src/client/components/modules/UploadMedia/index.js b/src/client/components/modules/UploadMedia/index.js index 9dcd2cc7f4..0ccf21de9c 100644 --- a/src/client/components/modules/UploadMedia/index.js +++ b/src/client/components/modules/UploadMedia/index.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { createPortal } from 'react-dom'; import Button from '../../controls/Button'; import api from '../../../api'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import './index.scss'; diff --git a/src/client/components/utilities/Locale/index.js b/src/client/components/utilities/Locale/index.js index 42da6f2493..3f3b82c4e3 100644 --- a/src/client/components/utilities/Locale/index.js +++ b/src/client/components/utilities/Locale/index.js @@ -2,7 +2,7 @@ import React, { createContext, useContext, useState, useEffect, } from 'react'; import PropTypes from 'prop-types'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import { useSearchParams } from '../SearchParams'; const defaultLocale = (config.localization && config.localization.defaultLocale) ? config.localization.defaultLocale : 'en'; diff --git a/src/client/components/utilities/RedirectToLogin/index.js b/src/client/components/utilities/RedirectToLogin/index.js index 1340cccba1..d122170de8 100644 --- a/src/client/components/utilities/RedirectToLogin/index.js +++ b/src/client/components/utilities/RedirectToLogin/index.js @@ -3,7 +3,7 @@ import { Redirect, } from 'react-router-dom'; import { useStatusList } from '../../modules/Status'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; const RedirectToLogin = () => { const { addStatus } = useStatusList(); diff --git a/src/client/components/views/CreateFirstUser/index.js b/src/client/components/views/CreateFirstUser/index.js index dab9517925..cb0c2ea82b 100644 --- a/src/client/components/views/CreateFirstUser/index.js +++ b/src/client/components/views/CreateFirstUser/index.js @@ -6,7 +6,7 @@ import ContentBlock from '../../layout/ContentBlock'; import Form from '../../forms/Form'; import RenderFields from '../../forms/RenderFields'; import FormSubmit from '../../forms/Submit'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import { useUser } from '../../data/User'; import './index.scss'; diff --git a/src/client/components/views/Dashboard/index.js b/src/client/components/views/Dashboard/index.js index af4a4c0206..805e875be5 100644 --- a/src/client/components/views/Dashboard/index.js +++ b/src/client/components/views/Dashboard/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import DefaultTemplate from '../../layout/DefaultTemplate'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import './index.scss'; diff --git a/src/client/components/views/Login/index.js b/src/client/components/views/Login/index.js index f6af456438..68a1c48caf 100644 --- a/src/client/components/views/Login/index.js +++ b/src/client/components/views/Login/index.js @@ -6,7 +6,7 @@ import Form from '../../forms/Form'; import Email from '../../forms/field-types/Email'; import Password from '../../forms/field-types/Password'; import FormSubmit from '../../forms/Submit'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import Button from '../../controls/Button'; import { useUser } from '../../data/User'; diff --git a/src/client/components/views/Logout/index.js b/src/client/components/views/Logout/index.js index e7f576cc28..4dd960ea67 100644 --- a/src/client/components/views/Logout/index.js +++ b/src/client/components/views/Logout/index.js @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import { useUser } from '../../data/User'; import ContentBlock from '../../layout/ContentBlock'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import Button from '../../controls/Button'; import './index.scss'; diff --git a/src/client/components/views/NotFound/index.js b/src/client/components/views/NotFound/index.js index cc1c0d9ec8..36ca0706e0 100644 --- a/src/client/components/views/NotFound/index.js +++ b/src/client/components/views/NotFound/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import config from '../../../config/sanitizedClientConfig'; +import config from '../../../securedConfig'; import Button from '../../controls/Button'; import DefaultTemplate from '../../layout/DefaultTemplate'; diff --git a/src/client/components/views/collections/Edit/index.js b/src/client/components/views/collections/Edit/index.js index 33527005f5..28123b7d1f 100644 --- a/src/client/components/views/collections/Edit/index.js +++ b/src/client/components/views/collections/Edit/index.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useRouteMatch, useHistory } from 'react-router-dom'; -import config from '../../../../config/sanitizedClientConfig'; +import config from '../../../../securedConfig'; import DefaultTemplate from '../../../layout/DefaultTemplate'; import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import Form from '../../../forms/Form'; diff --git a/src/client/components/views/collections/List/index.js b/src/client/components/views/collections/List/index.js index 88f47f5686..d438e77ad9 100644 --- a/src/client/components/views/collections/List/index.js +++ b/src/client/components/views/collections/List/index.js @@ -3,7 +3,7 @@ import { useLocation } from 'react-router-dom'; import queryString from 'qs'; import PropTypes from 'prop-types'; import usePayloadAPI from '../../../../hooks/usePayloadAPI'; -import config from '../../../../config/sanitizedClientConfig'; +import config from '../../../../securedConfig'; import DefaultTemplate from '../../../layout/DefaultTemplate'; import HeadingButton from '../../../modules/HeadingButton'; import SearchableTable from '../../../modules/SearchableTable'; diff --git a/src/client/components/views/globals/Edit/index.js b/src/client/components/views/globals/Edit/index.js index 2c864d1e5e..ea99ac77cc 100644 --- a/src/client/components/views/globals/Edit/index.js +++ b/src/client/components/views/globals/Edit/index.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import config from '../../../../config/sanitizedClientConfig'; +import config from '../../../../securedConfig'; import DefaultTemplate from '../../../layout/DefaultTemplate'; import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import Form from '../../../forms/Form'; diff --git a/src/client/config/index.js b/src/client/config/index.js deleted file mode 100644 index 334f8129ff..0000000000 --- a/src/client/config/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const sanitizeConfig = require('../utilities/sanitizeConfig'); - -module.exports = config => sanitizeConfig(config); diff --git a/src/client/config/sanitizedClientConfig.js b/src/client/securedConfig.js similarity index 63% rename from src/client/config/sanitizedClientConfig.js rename to src/client/securedConfig.js index a1bbb6e7e0..ee6e5c5ce2 100644 --- a/src/client/config/sanitizedClientConfig.js +++ b/src/client/securedConfig.js @@ -1,5 +1,5 @@ -const sanitizeConfig = require('../../utilities/sanitizeConfig'); -const secureConfig = require('../../utilities/secureConfig'); +const sanitizeConfig = require('../utilities/sanitizeConfig'); +const secureConfig = require('../utilities/secureConfig'); module.exports = (config) => { const sanitizedConfig = sanitizeConfig(config); diff --git a/src/collections/register.js b/src/collections/register.js new file mode 100644 index 0000000000..62707b6969 --- /dev/null +++ b/src/collections/register.js @@ -0,0 +1,19 @@ +const mongoose = require('mongoose'); +const collectionRoutes = require('./routes'); +const validate = require('./validate'); +const buildSchema = require('./buildSchema'); + +function registerCollections() { + this.config.collections.forEach((collection) => { + validate(collection, this.collections); + + this.collections[collection.slug] = { + model: mongoose.model(collection.slug, buildSchema(collection, this.config)), + config: collection, + }; + + this.router.use(collectionRoutes(this.collections[collection.slug])); + }); +} + +module.exports = registerCollections; diff --git a/src/collections/registerRoutes.js b/src/collections/routes.js similarity index 86% rename from src/collections/registerRoutes.js rename to src/collections/routes.js index 49d663faee..1ac3c078d4 100644 --- a/src/collections/registerRoutes.js +++ b/src/collections/routes.js @@ -1,3 +1,4 @@ +const express = require('express'); const requestHandlers = require('../mongoose/requestHandlers'); const bindModelMiddleware = require('../mongoose/bindModel'); const setModelLocaleMiddleware = require('../localization/setModelLocale'); @@ -8,7 +9,9 @@ const { query, create, findOne, destroy, update, } = requestHandlers; -const registerRoutes = ({ model, config }, router) => { +const router = express.Router(); + +const registerRoutes = ({ model, config }) => { router.all(`/${config.slug}*`, bindModelMiddleware(model), bindCollectionMiddleware(config), @@ -22,6 +25,8 @@ const registerRoutes = ({ model, config }, router) => { .get(loadPolicy(config.policies.read), findOne) .put(loadPolicy(config.policies.update), update) .delete(loadPolicy(config.policies.destroy), destroy); + + return router; }; module.exports = registerRoutes; diff --git a/src/express/middleware.js b/src/express/middleware.js new file mode 100644 index 0000000000..70c7842e6c --- /dev/null +++ b/src/express/middleware.js @@ -0,0 +1,35 @@ +const express = require('express'); +const passport = require('passport'); +const compression = require('compression'); +const bodyParser = require('body-parser'); +const methodOverride = require('method-override'); +const localizationMiddleware = require('../localization/middleware'); + +const middleware = (config) => { + return [ + passport.initialize(), + passport.session(), + express.json(), + methodOverride('X-HTTP-Method-Override'), + express.urlencoded({ extended: true }), + bodyParser.urlencoded({ extended: true }), + compression(config.compression), + localizationMiddleware(config.localization), + (req, res, next) => { + if (config.cors) { + if (config.cors.indexOf(req.headers.origin) > -1) { + res.setHeader('Access-Control-Allow-Origin', req.headers.origin); + res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); + } + + res.header('Access-Control-Allow-Headers', + 'Origin X-Requested-With, Content-Type, Accept, Authorization'); + res.header('Content-Language', config.localization.locale); + } + + next(); + }, + ]; +}; + +module.exports = middleware; diff --git a/src/globals/bindGlobalMiddleware.js b/src/globals/bindGlobalMiddleware.js deleted file mode 100644 index e67ec5c3ab..0000000000 --- a/src/globals/bindGlobalMiddleware.js +++ /dev/null @@ -1,8 +0,0 @@ -const bindGlobalMiddleware = (global) => { - return (req, res, next) => { - req.global = global; - next(); - }; -}; - -module.exports = bindGlobalMiddleware; diff --git a/src/globals/registerSchema.js b/src/globals/buildSchema.js similarity index 83% rename from src/globals/registerSchema.js rename to src/globals/buildSchema.js index 46d70b0b8e..21927cfd1e 100644 --- a/src/globals/registerSchema.js +++ b/src/globals/buildSchema.js @@ -4,13 +4,13 @@ const mongooseHidden = require('mongoose-hidden'); const buildSchema = require('../mongoose/schema/buildSchema'); const localizationPlugin = require('../localization/plugin'); -const registerSchema = (globalConfigs, config) => { +const registerSchema = (config) => { const globals = { - config: globalConfigs, + config: config.globals, model: {}, }; - if (globalConfigs && globalConfigs.length > 0) { + if (config.globals && config.globals.length > 0) { const globalsSchema = new mongoose.Schema({}, { discriminatorKey: 'globalType', timestamps: false }) .plugin(localizationPlugin, config.localization) .plugin(autopopulate) @@ -18,7 +18,7 @@ const registerSchema = (globalConfigs, config) => { const Globals = mongoose.model('globals', globalsSchema); - Object.values(globalConfigs).forEach((globalConfig) => { + Object.values(config.globals).forEach((globalConfig) => { const globalSchema = buildSchema(globalConfig.fields, config); globalSchema diff --git a/src/globals/middleware.js b/src/globals/middleware.js new file mode 100644 index 0000000000..a7424d1cd4 --- /dev/null +++ b/src/globals/middleware.js @@ -0,0 +1,8 @@ +const getMiddleware = (global) => { + return (req, res, next) => { + req.global = global; + next(); + }; +}; + +module.exports = getMiddleware; diff --git a/src/globals/register.js b/src/globals/register.js new file mode 100644 index 0000000000..26a79c4ee3 --- /dev/null +++ b/src/globals/register.js @@ -0,0 +1,12 @@ +const validate = require('./validate'); +const buildSchema = require('./buildSchema'); +const routes = require('./routes'); + + +function registerGlobals() { + validate(this.config.globals); + this.globals = buildSchema(this.config); + this.router.use(routes(this.config.globals, this.globals)); +} + +module.exports = registerGlobals; diff --git a/src/globals/registerRoutes.js b/src/globals/routes.js similarity index 65% rename from src/globals/registerRoutes.js rename to src/globals/routes.js index 49d49c362c..b005e8697a 100644 --- a/src/globals/registerRoutes.js +++ b/src/globals/routes.js @@ -1,18 +1,21 @@ +const express = require('express'); const requestHandlers = require('./requestHandlers'); const setModelLocaleMiddleware = require('../localization/setModelLocale'); const bindModelMiddleware = require('../mongoose/bindModel'); const loadPolicy = require('../auth/loadPolicy'); -const bindGlobalMiddleware = require('../globals/bindGlobalMiddleware'); +const getMiddleware = require('./middleware'); const { upsert, findOne } = requestHandlers; -const registerGlobals = (globals, router) => { +const router = express.Router(); + +const registerGlobals = (globalConfigs, Globals) => { router.all('/globals*', - bindModelMiddleware(globals.model), + bindModelMiddleware(Globals), setModelLocaleMiddleware()); - globals.config.forEach((global) => { - router.all(`/globals/${global.slug}`, bindGlobalMiddleware(global)); + globalConfigs.forEach((global) => { + router.all(`/globals/${global.slug}`, getMiddleware(global)); router .route(`/globals/${global.slug}`) @@ -20,6 +23,8 @@ const registerGlobals = (globals, router) => { .post(loadPolicy(global.policies.create), upsert) .put(loadPolicy(global.policies.update), upsert); }); + + return router; }; module.exports = registerGlobals; diff --git a/src/index.js b/src/index.js index 72e9a59ff4..e0e78ff14d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,45 +1,33 @@ -const mongoose = require('mongoose'); -const passportLocalMongoose = require('passport-local-mongoose'); -const connectMongoose = require('./init/connectMongoose'); -const registerExpressMiddleware = require('./init/registerExpressMiddleware'); -const initPassport = require('./init/passport'); -const initCORS = require('./init/cors'); -const initUploads = require('./init/uploads'); -const initWebpack = require('./init/webpack'); -const initUserAuth = require('./auth/init'); -const baseUserFields = require('./auth/baseFields'); -const baseUploadFields = require('./uploads/baseUploadFields'); -const baseImageFields = require('./uploads/baseImageFields'); -const registerUploadRoutes = require('./uploads/routes'); -const validateCollection = require('./collections/validate'); -const buildCollectionSchema = require('./collections/buildSchema'); -const registerCollectionRoutes = require('./collections/registerRoutes'); -const validateGlobals = require('./globals/validate'); -const registerGlobalSchema = require('./globals/registerSchema'); -const registerGlobalRoutes = require('./globals/registerRoutes'); +const express = require('express'); + +const connectMongoose = require('./mongoose/connect'); +const expressMiddleware = require('./express/middleware'); +const initWebpack = require('./webpack/init'); +const registerUser = require('./auth/register'); +const registerUpload = require('./uploads/register'); +const registerCollections = require('./collections/register'); +const registerGlobals = require('./globals/register'); const sanitizeConfig = require('./utilities/sanitizeConfig'); class Payload { constructor(options) { + this.config = sanitizeConfig(options.config); + this.express = options.express; + this.router = express.Router(); this.collections = {}; - this.registerUser.bind(this); - this.registerUpload.bind(this); - this.registerGlobals.bind(this); - this.registerCollections.bind(this); + + this.registerUser = registerUser.bind(this); + this.registerUpload = registerUpload.bind(this); + this.registerCollections = registerCollections.bind(this); + this.registerGlobals = registerGlobals.bind(this); + this.getCollections.bind(this); this.getGlobals.bind(this); - // Bind options, app, router - this.app = options.app; - this.config = sanitizeConfig(options.config); - this.router = options.router; - // Setup & initialization connectMongoose(this.config.mongoURL); - registerExpressMiddleware(this.app, this.config, this.router); - initPassport(this.app); - initUploads(this.app, this.config); - initCORS(this.app, this.config); + + this.router.use(...expressMiddleware(this.config)); // Register and bind required collections this.registerUser(); @@ -51,67 +39,16 @@ class Payload { // Register globals this.registerGlobals(); - // Enable client webpack - if (!this.config.disableAdmin) initWebpack(this.app, this.config); - } + // Enable client + if (!this.config.disableAdmin) { + this.express.use(initWebpack(this.config)); + } - registerUser() { - this.config.user.fields.push(...baseUserFields); - const userSchema = buildCollectionSchema(this.config.user, this.config); - userSchema.plugin(passportLocalMongoose, { usernameField: this.config.user.auth.useAsUsername }); + // Bind router to API + this.express.use(this.config.routes.api, this.router); - this.User = mongoose.model(this.config.user.labels.singular, userSchema); - initUserAuth(this.User, this.config, this.router); - - registerCollectionRoutes({ - model: this.User, - config: this.config.user, - }, this.router); - } - - registerUpload() { - // TODO: mongooseHidden on our upload model is hiding all the fields - const uploadSchema = buildCollectionSchema( - this.config.upload, - this.config, - { discriminatorKey: 'type' }, - ); - - uploadSchema.add(baseUploadFields); - - const imageSchema = new mongoose.Schema(baseImageFields, { - discriminatorKey: 'type', - }); - - this.Upload = mongoose.model(this.config.upload.labels.singular, uploadSchema); - // TODO: image type hard coded, but in the future we need some way of customizing how uploads are handled in customizable pattern - this.Upload.discriminator('image', imageSchema); - - registerUploadRoutes(this.Upload, this.config, this.router); - - registerCollectionRoutes({ - model: this.Upload, - config: this.config.upload, - }, this.router); - } - - registerCollections() { - this.config.collections.forEach((collection) => { - validateCollection(collection, this.collections); - - this.collections[collection.slug] = { - model: mongoose.model(collection.slug, buildCollectionSchema(collection, this.config)), - config: collection, - }; - - registerCollectionRoutes(this.collections[collection.slug], this.router); - }); - } - - registerGlobals() { - validateGlobals(this.config.globals); - this.globals = registerGlobalSchema(this.config.globals, this.config); - registerGlobalRoutes(this.globals, this.router); + // Bind static + this.express.use(this.config.staticURL, express.static(this.config.staticDir)); } getCollections() { diff --git a/src/init/cors.js b/src/init/cors.js deleted file mode 100644 index 2499f4fe4f..0000000000 --- a/src/init/cors.js +++ /dev/null @@ -1,18 +0,0 @@ -const initCORS = (app, config) => { - if (config.cors) { - app.use((req, res, next) => { - if (config.cors.indexOf(req.headers.origin) > -1) { - res.setHeader('Access-Control-Allow-Origin', req.headers.origin); - res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); - } - - res.header('Access-Control-Allow-Headers', - 'Origin X-Requested-With, Content-Type, Accept, Authorization'); - res.header('Content-Language', config.localization.locale); - - next(); - }); - } -}; - -module.exports = initCORS; diff --git a/src/init/passport.js b/src/init/passport.js deleted file mode 100644 index 29ac1d32e0..0000000000 --- a/src/init/passport.js +++ /dev/null @@ -1,8 +0,0 @@ -const passport = require('passport'); - -const initPassport = (app) => { - app.use(passport.initialize()); - app.use(passport.session()); -}; - -module.exports = initPassport; diff --git a/src/init/registerExpressMiddleware.js b/src/init/registerExpressMiddleware.js deleted file mode 100644 index 444e4d37fb..0000000000 --- a/src/init/registerExpressMiddleware.js +++ /dev/null @@ -1,17 +0,0 @@ -const express = require('express'); -const compression = require('compression'); -const bodyParser = require('body-parser'); -const methodOverride = require('method-override'); -const localizationMiddleware = require('../localization/middleware'); - -const registerExpressMiddleware = (app, config, router) => { - app.use(express.json()); - app.use(methodOverride('X-HTTP-Method-Override')); - app.use(express.urlencoded({ extended: true })); - app.use(bodyParser.urlencoded({ extended: true })); - app.use(compression(config.compression)); - app.use(localizationMiddleware(config.localization)); - app.use(router); -}; - -module.exports = registerExpressMiddleware; diff --git a/src/init/uploads.js b/src/init/uploads.js deleted file mode 100644 index 7e522a6b37..0000000000 --- a/src/init/uploads.js +++ /dev/null @@ -1,8 +0,0 @@ -const express = require('express'); - -const initUploads = (app, config) => { - const staticUrl = config.staticUrl ? config.staticUrl : `/${config.staticDir}`; - app.use(staticUrl, express.static(config.staticDir)); -}; - -module.exports = initUploads; diff --git a/src/init/connectMongoose.js b/src/mongoose/connect.js similarity index 100% rename from src/init/connectMongoose.js rename to src/mongoose/connect.js diff --git a/src/routes/init.js b/src/routes/init.js deleted file mode 100644 index c37aa1e76a..0000000000 --- a/src/routes/init.js +++ /dev/null @@ -1,19 +0,0 @@ -const express = require('express'); - -const router = express.Router(); -const initRoutes = (User) => { - router - .route('/init') - .get((req, res) => { - User.countDocuments({}, (err, count) => { - if (err) res.status(200).json({ error: err }); - return count >= 1 - ? res.status(200).json({ initialized: true }) - : res.status(200).json({ initialized: false }); - }); - }); - - return router; -}; - -module.exports = initRoutes; diff --git a/src/uploads/register.js b/src/uploads/register.js new file mode 100644 index 0000000000..cc134e1fb2 --- /dev/null +++ b/src/uploads/register.js @@ -0,0 +1,35 @@ +const mongoose = require('mongoose'); +const collectionRoutes = require('../collections/routes'); +const uploadRoutes = require('./routes'); +const baseUploadFields = require('./baseUploadFields'); +const baseImageFields = require('./baseImageFields'); +const buildCollectionSchema = require('../collections/buildSchema'); + +function registerUpload() { + // TODO: mongooseHidden on our upload model is hiding all the fields + const uploadSchema = buildCollectionSchema( + this.config.upload, + this.config, + { discriminatorKey: 'type' }, + ); + + uploadSchema.add(baseUploadFields); + + const imageSchema = new mongoose.Schema(baseImageFields, { + discriminatorKey: 'type', + }); + + this.Upload = mongoose.model(this.config.upload.labels.singular, uploadSchema); + + // TODO: image type hard coded, but in the future we need some way of customizing how uploads are handled in customizable pattern + this.Upload.discriminator('image', imageSchema); + + this.router.use(uploadRoutes(this.config, this.Upload)); + + this.router.use(collectionRoutes({ + model: this.Upload, + config: this.config.upload, + })); +} + +module.exports = registerUpload; diff --git a/src/uploads/routes.js b/src/uploads/routes.js index cdc1101a67..632741e401 100644 --- a/src/uploads/routes.js +++ b/src/uploads/routes.js @@ -1,10 +1,13 @@ +const express = require('express'); const passport = require('passport'); const fileUpload = require('express-fileupload'); const { upload, update } = require('./requestHandlers'); const uploadMiddleware = require('./middleware'); const setModelLocaleMiddleware = require('../localization/setModelLocale'); -const uploadRoutes = (Upload, config, router) => { +const router = express.Router(); + +const uploadRoutes = (config, Upload) => { const { upload: uploadConfig } = config; router.all(`/${uploadConfig.slug}*`, diff --git a/src/client/config/getStyleLoaders.js b/src/webpack/getStyleLoaders.js similarity index 100% rename from src/client/config/getStyleLoaders.js rename to src/webpack/getStyleLoaders.js diff --git a/src/client/config/getWebpackDevConfig.js b/src/webpack/getWebpackDevConfig.js similarity index 87% rename from src/client/config/getWebpackDevConfig.js rename to src/webpack/getWebpackDevConfig.js index 76bbddd93e..6a41aff53b 100644 --- a/src/client/config/getWebpackDevConfig.js +++ b/src/webpack/getWebpackDevConfig.js @@ -6,7 +6,10 @@ const getStyleLoaders = require('./getStyleLoaders'); module.exports = (config) => { return { entry: { - main: [path.resolve(__dirname, '../../../node_modules/webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000'), path.resolve(__dirname, '../components/index.js')], + main: [ + path.resolve(__dirname, '../../node_modules/webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000'), + path.resolve(__dirname, '../client/components/index.js'), + ], }, output: { path: '/', @@ -21,11 +24,11 @@ module.exports = (config) => { node: { __dirname: true, }, - resolveLoader: { modules: [path.join(__dirname, '../../../node_modules')] }, + resolveLoader: { modules: [path.join(__dirname, '../../node_modules')] }, module: { rules: [ { - test: require.resolve('../components/customComponents'), + test: require.resolve('../client/components/customComponents'), use: [ { loader: 'val-loader', @@ -34,7 +37,7 @@ module.exports = (config) => { ], }, { - test: require.resolve('./sanitizedClientConfig'), + test: require.resolve('../client/securedConfig'), use: [ { loader: 'val-loader', @@ -116,13 +119,13 @@ module.exports = (config) => { }, plugins: [ new HtmlWebpackPlugin({ - template: path.resolve(__dirname, '../index.html'), + template: path.resolve(__dirname, '../client/index.html'), filename: './index.html', }), new webpack.HotModuleReplacementPlugin(), ], resolve: { - modules: ['node_modules', path.resolve(__dirname, '../../../node_modules')], + modules: ['node_modules', path.resolve(__dirname, '../../node_modules')], alias: { 'payload-scss-overrides': config.paths.scssOverrides, }, diff --git a/src/client/config/getWebpackProdConfig.js b/src/webpack/getWebpackProdConfig.js similarity index 100% rename from src/client/config/getWebpackProdConfig.js rename to src/webpack/getWebpackProdConfig.js diff --git a/src/init/webpack.js b/src/webpack/init.js similarity index 55% rename from src/init/webpack.js rename to src/webpack/init.js index 3b5856eefb..eed3cc7e6e 100644 --- a/src/init/webpack.js +++ b/src/webpack/init.js @@ -1,28 +1,31 @@ const webpack = require('webpack'); +const express = require('express'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); -const getWebpackDevConfig = require('../client/config/getWebpackDevConfig'); +const getWebpackDevConfig = require('./getWebpackDevConfig'); -const initWebpack = (app, config) => { +const router = express.Router(); + +const initWebpack = (config) => { const webpackDevConfig = getWebpackDevConfig(config); const compiler = webpack(webpackDevConfig); - app.use(webpackDevMiddleware(compiler, { + router.use(webpackDevMiddleware(compiler, { publicPath: webpackDevConfig.output.publicPath, })); - app.use(webpackHotMiddleware(compiler)); + router.use(webpackHotMiddleware(compiler)); - app.get(`${config.routes.admin}*`, (req, res, next) => { + router.get(`${config.routes.admin}*`, (req, res, next) => { compiler.outputFileSystem.readFile('/index.html', (err, result) => { if (err) { return next(err); } - res.set('content-type', 'text/html'); - res.send(result); - res.end(); + return res.set('content-type', 'text/html').send(result); }); }); + + return router; }; module.exports = initWebpack;