@reldens/cms 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/reldens-admin-client.css +11 -0
- package/admin/templates/cache-clean-button.html +4 -0
- package/admin/templates/fields/view/textarea.html +1 -1
- package/bin/reldens-cms-generate-entities.js +85 -18
- package/bin/reldens-cms.js +6 -6
- package/lib/admin-manager/contents-builder.js +256 -0
- package/lib/admin-manager/router-contents.js +576 -0
- package/lib/admin-manager/router.js +208 -0
- package/lib/admin-manager.js +114 -990
- package/lib/cache/add-cache-button-subscriber.js +101 -0
- package/lib/cache/cache-manager.js +129 -0
- package/lib/cache/cache-routes-handler.js +76 -0
- package/lib/cms-pages-route-manager.js +31 -19
- package/lib/frontend.js +192 -52
- package/lib/installer.js +5 -2
- package/lib/json-fields-parser.js +74 -0
- package/lib/manager.js +7 -1
- package/lib/template-engine.js +79 -27
- package/lib/templates-list.js +1 -0
- package/migrations/default-homepage.sql +6 -6
- package/migrations/install.sql +4 -3
- package/package.json +2 -2
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Router
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Logger } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class Router
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.app = props.app;
|
|
15
|
+
this.applicationFramework = props.applicationFramework;
|
|
16
|
+
this.bodyParser = props.bodyParser;
|
|
17
|
+
this.session = props.session;
|
|
18
|
+
this.secret = props.secret;
|
|
19
|
+
this.rootPath = props.rootPath;
|
|
20
|
+
this.adminRoleId = props.adminRoleId;
|
|
21
|
+
this.authenticationCallback = props.authenticationCallback;
|
|
22
|
+
this.uploaderFactory = props.uploaderFactory;
|
|
23
|
+
this.buckets = props.buckets;
|
|
24
|
+
this.blackList = props.blackList;
|
|
25
|
+
this.loginPath = props.loginPath;
|
|
26
|
+
this.logoutPath = props.logoutPath;
|
|
27
|
+
this.viewPath = props.viewPath;
|
|
28
|
+
this.editPath = props.editPath;
|
|
29
|
+
this.savePath = props.savePath;
|
|
30
|
+
this.deletePath = props.deletePath;
|
|
31
|
+
this.resources = props.resources;
|
|
32
|
+
this.emitEvent = props.emitEvent;
|
|
33
|
+
this.fetchUploadProperties = props.fetchUploadProperties;
|
|
34
|
+
this.adminContents = props.adminContents;
|
|
35
|
+
this.generateListRouteContent = props.generateListRouteContent;
|
|
36
|
+
this.generateViewRouteContent = props.generateViewRouteContent;
|
|
37
|
+
this.generateEditRouteContent = props.generateEditRouteContent;
|
|
38
|
+
this.processDeleteEntities = props.processDeleteEntities;
|
|
39
|
+
this.processSaveEntity = props.processSaveEntity;
|
|
40
|
+
this.setupAdminRouter();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setupAdminRouter()
|
|
44
|
+
{
|
|
45
|
+
if(!this.applicationFramework){
|
|
46
|
+
Logger.critical('ApplicationFramework is required for AdminRouter setup.');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
this.adminRouter = this.applicationFramework.Router();
|
|
50
|
+
if(this.session){
|
|
51
|
+
if(!this.secret){
|
|
52
|
+
Logger.warning('Admin Manager "secret" key was not provided.');
|
|
53
|
+
}
|
|
54
|
+
this.adminRouter.use(this.session({secret: this.secret, resave: false, saveUninitialized: true}));
|
|
55
|
+
}
|
|
56
|
+
if(!this.bodyParser){
|
|
57
|
+
Logger.critical('BodyParser is required for AdminRouter setup.');
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
this.adminRouter.use(this.bodyParser.json());
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setupAdminRoutes()
|
|
65
|
+
{
|
|
66
|
+
this.adminRouter.get(this.loginPath, async (req, res) => {
|
|
67
|
+
return res.send(this.adminContents().login);
|
|
68
|
+
});
|
|
69
|
+
this.adminRouter.post(this.loginPath, async (req, res) => {
|
|
70
|
+
let { email, password } = req.body;
|
|
71
|
+
let loginResult = await this.authenticationCallback(email, password, this.adminRoleId);
|
|
72
|
+
if(loginResult){
|
|
73
|
+
req.session.user = loginResult;
|
|
74
|
+
return res.redirect(this.rootPath);
|
|
75
|
+
}
|
|
76
|
+
return res.redirect(this.rootPath+this.loginPath+'?login-error=true');
|
|
77
|
+
});
|
|
78
|
+
this.adminRouter.get('/', this.isAuthenticated.bind(this), async (req, res) => {
|
|
79
|
+
return res.send(this.adminContents().dashboard);
|
|
80
|
+
});
|
|
81
|
+
this.adminRouter.get(this.logoutPath, (req, res) => {
|
|
82
|
+
req.session.destroy();
|
|
83
|
+
res.redirect(this.rootPath+this.loginPath);
|
|
84
|
+
});
|
|
85
|
+
this.app.use(this.rootPath, this.adminRouter);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async setupEntitiesRoutes()
|
|
89
|
+
{
|
|
90
|
+
let resources = this.resources();
|
|
91
|
+
if(!resources || 0 === resources.length){
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
for(let driverResource of resources){
|
|
95
|
+
let entityPath = driverResource.entityPath;
|
|
96
|
+
let entityRoute = '/'+entityPath;
|
|
97
|
+
this.adminRouter.get(entityRoute, this.isAuthenticated.bind(this), async (req, res) => {
|
|
98
|
+
return res.send(await this.generateListRouteContent(req, driverResource, entityPath));
|
|
99
|
+
});
|
|
100
|
+
this.adminRouter.post(entityRoute, this.isAuthenticated.bind(this), async (req, res) => {
|
|
101
|
+
return res.send(await this.generateListRouteContent(req, driverResource, entityPath));
|
|
102
|
+
});
|
|
103
|
+
this.adminRouter.get(entityRoute+this.viewPath, this.isAuthenticated.bind(this), async (req, res) => {
|
|
104
|
+
let routeContents = await this.generateViewRouteContent(req, driverResource, entityPath);
|
|
105
|
+
if('' === routeContents){
|
|
106
|
+
return res.redirect(this.rootPath+'/'+entityPath+'?result=errorView');
|
|
107
|
+
}
|
|
108
|
+
return res.send(routeContents);
|
|
109
|
+
});
|
|
110
|
+
this.adminRouter.get(entityRoute+this.editPath, this.isAuthenticated.bind(this), async (req, res) => {
|
|
111
|
+
await this.emitEvent('reldens.adminBeforeEntityEdit', {
|
|
112
|
+
req,
|
|
113
|
+
res,
|
|
114
|
+
driverResource,
|
|
115
|
+
entityPath
|
|
116
|
+
});
|
|
117
|
+
let routeContents = await this.generateEditRouteContent(req, driverResource, entityPath);
|
|
118
|
+
if('' === routeContents){
|
|
119
|
+
return res.redirect(this.rootPath+'/'+entityPath+'?result=errorEdit');
|
|
120
|
+
}
|
|
121
|
+
return res.send(routeContents);
|
|
122
|
+
});
|
|
123
|
+
this.setupSavePath(entityRoute, driverResource, entityPath);
|
|
124
|
+
this.adminRouter.post(entityRoute+this.deletePath, this.isAuthenticated.bind(this), async (req, res) => {
|
|
125
|
+
return res.redirect(await this.processDeleteEntities(req, res, driverResource, entityPath));
|
|
126
|
+
});
|
|
127
|
+
await this.emitEvent('reldens.setupEntitiesRoutes', {
|
|
128
|
+
entityPath,
|
|
129
|
+
entityRoute,
|
|
130
|
+
driverResource
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setupSavePath(entityRoute, driverResource, entityPath)
|
|
136
|
+
{
|
|
137
|
+
let uploadProperties = this.fetchUploadProperties(driverResource);
|
|
138
|
+
if(0 === Object.keys(uploadProperties || {}).length){
|
|
139
|
+
this.adminRouter.post(
|
|
140
|
+
entityRoute+this.savePath,
|
|
141
|
+
this.isAuthenticated.bind(this),
|
|
142
|
+
async (req, res) => {
|
|
143
|
+
await this.emitEvent('reldens.adminBeforeEntitySave', {
|
|
144
|
+
req,
|
|
145
|
+
res,
|
|
146
|
+
driverResource,
|
|
147
|
+
entityPath
|
|
148
|
+
});
|
|
149
|
+
return res.redirect(await this.processSaveEntity(req, res, driverResource, entityPath));
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
let fields = [];
|
|
155
|
+
let allowedFileTypes = {};
|
|
156
|
+
for(let uploadPropertyKey of Object.keys(uploadProperties)){
|
|
157
|
+
let property = uploadProperties[uploadPropertyKey];
|
|
158
|
+
allowedFileTypes[uploadPropertyKey] = property.allowedTypes || false;
|
|
159
|
+
let field = {name: uploadPropertyKey};
|
|
160
|
+
if(!property.isArray){
|
|
161
|
+
field.maxCount = 1;
|
|
162
|
+
}
|
|
163
|
+
fields.push(field);
|
|
164
|
+
this.buckets[uploadPropertyKey] = property.bucket;
|
|
165
|
+
}
|
|
166
|
+
this.adminRouter.post(
|
|
167
|
+
entityRoute + this.savePath,
|
|
168
|
+
this.isAuthenticated.bind(this),
|
|
169
|
+
this.uploaderFactory.createUploader(fields, this.buckets, allowedFileTypes),
|
|
170
|
+
async (req, res) => {
|
|
171
|
+
await this.emitEvent('reldens.adminBeforeEntitySave', {
|
|
172
|
+
req,
|
|
173
|
+
res,
|
|
174
|
+
driverResource,
|
|
175
|
+
entityPath
|
|
176
|
+
});
|
|
177
|
+
return res.redirect(await this.processSaveEntity(req, res, driverResource, entityPath));
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
isAuthenticated(req, res, next)
|
|
183
|
+
{
|
|
184
|
+
let allowContinue = {result: true, callback: null};
|
|
185
|
+
let event = {req, res, next, allowContinue};
|
|
186
|
+
this.emitEvent('reldens.adminIsAuthenticated', event);
|
|
187
|
+
let returnPath = this.rootPath+this.loginPath;
|
|
188
|
+
if(false === allowContinue.result){
|
|
189
|
+
return res.redirect(returnPath);
|
|
190
|
+
}
|
|
191
|
+
if(null !== allowContinue.callback){
|
|
192
|
+
return allowContinue.callback(event);
|
|
193
|
+
}
|
|
194
|
+
let user = req.session?.user;
|
|
195
|
+
if(!user){
|
|
196
|
+
return res.redirect(returnPath);
|
|
197
|
+
}
|
|
198
|
+
let userBlackList = this.blackList[user.role_id] || [];
|
|
199
|
+
if(-1 !== userBlackList.indexOf(req.path)){
|
|
200
|
+
let referrer = String(req.headers?.referer || '');
|
|
201
|
+
return res.redirect('' !== referrer ? referrer : returnPath);
|
|
202
|
+
}
|
|
203
|
+
return next();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports.Router = Router;
|