UNPKG

3.33 kBJavaScriptView Raw
1require('dotenv').config();
2require('q3-locale');
3
4const { get } = require('lodash');
5const walker = require('q3-core-walker');
6const { AccessControl } = require('q3-core-access');
7const {
8 handleUncaughtExceptions,
9} = require('q3-core-responder');
10const i18next = require('i18next');
11const { middleware } = require('q3-core-composer');
12const { config } = require('q3-core-mailer');
13const path = require('path');
14const locale = require('q3-locale');
15const runner = require('./config');
16const app = require('./config/express');
17const io = require('./config/socket');
18const mongoose = require('./config/mongoose');
19const models = require('./models');
20
21/**
22 * When testing, frameworks like supertest attach listeners.
23 */
24const connectToDB = (res, rej) => (err) => {
25 if (err) return rej(err);
26 app.use(handleUncaughtExceptions);
27 if (process.env.NODE_ENV !== 'test') {
28 app.listen(process.env.PORT);
29 io.listen();
30 }
31
32 return res(null);
33};
34
35const registerLocale = ({ location }) => () =>
36 new Promise((resolve) => {
37 try {
38 locale(location);
39 } catch (e) {
40 // noop
41 }
42
43 resolve();
44 });
45
46/**
47 * See q3-core-mailer for more details.
48 * Essentially, it uses the location to register event handlers by the file system architecture.
49 */
50const registerChores = ({ location, chores }) => () =>
51 chores && location ? config(chores).walk(location) : null;
52
53/**
54 * Uses the package.json file to locate app index.
55 */
56const locate = () => {
57 try {
58 const root = process.cwd();
59 // eslint-disable-next-line
60 const r = require(path.resolve(root, './package.json'));
61 return path.parse(path.resolve(root, r.main)).dir;
62 } catch (e) {
63 return null;
64 }
65};
66
67const Q3 = {
68 protect(grants = []) {
69 AccessControl.init(grants);
70 return this;
71 },
72
73 config(args = {}) {
74 const location = locate();
75
76 if (!location && !args.location)
77 throw new Error('App requires a location');
78
79 Object.assign(
80 app.locals,
81 {
82 location,
83 },
84 args,
85 );
86
87 return this;
88 },
89
90 routes() {
91 const { location } = app.locals;
92 app.use(middleware(models.Users));
93 runner();
94
95 app.use(walker(__dirname));
96 app.use(walker(location));
97 return this;
98 },
99
100 model(name) {
101 if (!(name in mongoose.models))
102 throw new Error('Unknown model');
103
104 return get(mongoose.models, name);
105 },
106
107 setModel(name, Schema) {
108 return mongoose.model(name, Schema);
109 },
110
111 connect: async (directConnectionString) =>
112 new Promise((resolve, reject) =>
113 directConnectionString
114 ? mongoose.connect(directConnectionString, (e) => {
115 if (e) reject(e);
116 resolve();
117 })
118 : mongoose
119 .connect(
120 process.env.CONNECTION,
121 connectToDB(resolve, reject),
122 )
123 // register only on the main process
124 .then(registerChores(app.locals)),
125 )
126 .then(registerLocale(app.locals))
127 .catch((e) => {
128 // eslint-disable-next-line
129 console.error(e);
130 process.exit(0);
131 }),
132};
133
134Q3.$app = app;
135Q3.$mongoose = mongoose;
136Q3.$i18 = i18next;
137
138Object.assign(Q3, models);
139module.exports = Q3;