larvitcms 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/.eslintrc CHANGED
@@ -1,88 +1,86 @@
1
1
  {
2
- "root": true,
3
- "env": {
4
- "es6": true,
5
- "mocha": true,
6
- "node": true
7
- },
8
- "rules": {
9
- "array-bracket-newline": ["error", "consistent"],
10
- "array-bracket-spacing": ["error", "never"],
11
- "block-spacing": ["error", "always"],
12
- "brace-style": ["error", "1tbs", {"allowSingleLine": true}],
13
- "capitalized-comments": ["error", "always", {"ignoreConsecutiveComments": true}],
14
- "comma-dangle": ["error", "never"],
15
- "comma-spacing": ["error", {"before": false, "after": true}],
16
- "comma-style": ["error", "last"],
17
- "computed-property-spacing": ["error", "never"],
18
- "consistent-this": ["error", "that"],
19
- "eol-last": ["error", "always"],
20
- "eqeqeq": ["warn", "always"],
21
- "func-call-spacing": ["error", "never"],
22
- "func-style": ["error", "declaration", {"allowArrowFunctions": true}],
23
- "function-paren-newline": ["error", "multiline"],
24
- "indent": ["error", "tab"],
25
- "key-spacing": [
26
- "error",
27
- {"beforeColon": false, "afterColon": true, "mode": "strict"}
28
- ],
29
- "keyword-spacing": ["error", {"before": true, "after": true}],
30
- "linebreak-style": ["error", "unix"],
31
- "lines-around-comment": ["error", {"beforeBlockComment": true, "afterBlockComment": false}],
32
- "lines-between-class-members": ["error", "always"],
33
- "multiline-ternary": ["error", "never"],
34
- "new-cap": ["error"],
35
- "new-parens": ["error"],
36
- "newline-per-chained-call": ["error"],
37
- "no-dupe-args": ["error"],
38
- "no-dupe-keys": ["error"],
39
- "no-invalid-regexp": ["error"],
40
- "no-irregular-whitespace": ["error", {"skipStrings": true, "skipComments": true, "skipRegExps": true, "skipTemplates": true}],
41
- "no-lonely-if": ["error"],
42
- "no-mixed-operators": ["error"],
43
- "no-mixed-requires": ["off"],
44
- "no-mixed-spaces-and-tabs": ["error"],
45
- "no-multi-spaces": ["error", { "ignoreEOLComments": false }],
46
- "no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 1, "maxBOF": 0}],
47
- "no-process-exit": ["off"],
48
- "no-redeclare": ["error"],
49
- "no-sequences": ["error"],
50
- "no-shadow": ["off"],
51
- "no-tabs": ["error", { "allowIndentationTabs": true }],
52
- "no-trailing-spaces": ["error", {"ignoreComments": true}],
53
- "no-underscore-dangle": ["off"],
54
- "no-unexpected-multiline": ["error"],
55
- "no-unreachable": ["error"],
56
- "no-unused-expressions": ["error"],
57
- "no-unused-vars": ["error", {"caughtErrors": "all"}],
58
- "no-use-before-define": ["error", {"functions": true, "classes": true, "variables": true}],
59
- "no-var": ["error"],
60
- "no-whitespace-before-property": ["error"],
61
- "nonblock-statement-body-position": ["error", "beside"],
62
- "one-var": ["error", "never"],
63
- "padded-blocks": ["error", "never"],
64
- "padding-line-between-statements": [
65
- "error",
66
- {"blankLine": "always", "prev": "*", "next": "return"},
67
- {"blankLine": "always", "prev": ["const", "let"], "next": "*"},
68
- {"blankLine": "any", "prev": ["const", "let"], "next": ["const", "let"]}
69
- ],
70
- "quote-props": ["error", "as-needed"],
71
- "quotes": ["error", "single"],
72
- "semi-spacing": ["error", {"before": false, "after": true}],
73
- "semi-style": ["error", "last"],
74
- "semi": ["error", "always"],
75
- "space-before-blocks": ["error", "always"],
76
- "space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
77
- "space-in-parens": ["error", "never"],
78
- "space-infix-ops": ["error"],
79
- "space-unary-ops": ["error", {"words": true, "nonwords": false}],
80
- "spaced-comment": ["error", "always"],
81
- "strict": ["error", "global"],
82
- "template-tag-spacing": ["error", "never"],
83
- "unicode-bom": ["error", "never"],
84
- "valid-jsdoc": ["error", {"requireReturn": false}],
85
- "valid-typeof": ["error"],
86
- "vars-on-top": ["off"]
87
- }
88
- }
2
+ "root": true,
3
+ "parserOptions": {
4
+ "ecmaVersion": 2020
5
+ },
6
+ "env": {
7
+ "es6": true,
8
+ "mocha": true,
9
+ "node": true
10
+ },
11
+ "rules": {
12
+ "array-bracket-newline": ["error", "consistent"],
13
+ "array-bracket-spacing": ["error", "never"],
14
+ "block-spacing": ["error", "always"],
15
+ "brace-style": ["error", "1tbs", {"allowSingleLine": true}],
16
+ "comma-dangle": ["error", "always-multiline"],
17
+ "comma-spacing": ["error", {"before": false, "after": true}],
18
+ "comma-style": ["error", "last"],
19
+ "computed-property-spacing": ["error", "never"],
20
+ "consistent-this": ["error", "that"],
21
+ "eol-last": ["error", "always"],
22
+ "eqeqeq": ["warn", "always"],
23
+ "func-call-spacing": ["error", "never"],
24
+ "func-style": ["error", "declaration", {"allowArrowFunctions": true}],
25
+ "function-paren-newline": ["error", "multiline"],
26
+ "indent": ["error", "tab"],
27
+ "key-spacing": [
28
+ "error",
29
+ {"beforeColon": false, "afterColon": true, "mode": "strict"}
30
+ ],
31
+ "keyword-spacing": ["error", {"before": true, "after": true}],
32
+ "linebreak-style": ["error", "unix"],
33
+ "lines-around-comment": ["error", {"beforeBlockComment": true, "afterBlockComment": false}],
34
+ "lines-between-class-members": ["error", "always"],
35
+ "new-cap": ["error"],
36
+ "new-parens": ["error"],
37
+ "no-dupe-args": ["error"],
38
+ "no-dupe-keys": ["error"],
39
+ "no-invalid-regexp": ["error"],
40
+ "no-irregular-whitespace": ["error", {"skipStrings": true, "skipComments": true, "skipRegExps": true, "skipTemplates": true}],
41
+ "no-lonely-if": ["error"],
42
+ "no-mixed-operators": ["error"],
43
+ "no-mixed-requires": ["off"],
44
+ "no-mixed-spaces-and-tabs": ["error"],
45
+ "no-multi-spaces": ["error", { "ignoreEOLComments": false }],
46
+ "no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 1, "maxBOF": 0}],
47
+ "no-process-exit": ["off"],
48
+ "no-redeclare": ["error"],
49
+ "no-sequences": ["error"],
50
+ "no-shadow": ["off"],
51
+ "no-tabs": ["error", { "allowIndentationTabs": true }],
52
+ "no-trailing-spaces": ["error", {"ignoreComments": true}],
53
+ "no-underscore-dangle": ["off"],
54
+ "no-unexpected-multiline": ["error"],
55
+ "no-unreachable": ["error"],
56
+ "no-unused-expressions": ["error"],
57
+ "no-unused-vars": ["error", {"caughtErrors": "all"}],
58
+ "no-use-before-define": ["error", {"functions": true, "classes": true, "variables": true}],
59
+ "no-var": ["error"],
60
+ "no-whitespace-before-property": ["error"],
61
+ "nonblock-statement-body-position": ["error", "beside"],
62
+ "one-var": ["error", "never"],
63
+ "padding-line-between-statements": [
64
+ "error",
65
+ {"blankLine": "always", "prev": "*", "next": "return"},
66
+ {"blankLine": "any", "prev": ["const", "let"], "next": "*"}
67
+ ],
68
+ "quote-props": ["error", "as-needed"],
69
+ "quotes": ["error", "single"],
70
+ "semi-spacing": ["error", {"before": false, "after": true}],
71
+ "semi-style": ["error", "last"],
72
+ "semi": ["error", "always"],
73
+ "space-before-blocks": ["error", "always"],
74
+ "space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
75
+ "space-in-parens": ["error", "never"],
76
+ "space-infix-ops": ["error"],
77
+ "space-unary-ops": ["error", {"words": true, "nonwords": false}],
78
+ "spaced-comment": ["error", "always"],
79
+ "strict": ["error", "global"],
80
+ "template-tag-spacing": ["error", "never"],
81
+ "unicode-bom": ["error", "never"],
82
+ "valid-jsdoc": ["error", {"requireReturn": false}],
83
+ "valid-typeof": ["error"],
84
+ "vars-on-top": ["off"]
85
+ }
86
+ }
@@ -0,0 +1,43 @@
1
+ name: larvitsession CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ matrix:
11
+ node-version: [14.x, 16.x]
12
+
13
+ steps:
14
+ - uses: getong/mariadb-action@v1.1
15
+ with:
16
+ host port: 3306
17
+ container port: 3306
18
+ mariadb version: '10.7'
19
+ mysql database: 'test'
20
+ mysql root password: 'test'
21
+
22
+ - uses: actions/checkout@v2
23
+ - name: Use Node.js ${{ matrix.node-version }}
24
+ uses: actions/setup-node@v2
25
+ with:
26
+ node-version: ${{ matrix.node-version }}
27
+ cache: 'npm'
28
+ - run: npm ci
29
+ - shell: bash
30
+ run: |
31
+ cat << EOF > ./config/db_test.json
32
+ {
33
+ "connectionLimit": 10,
34
+ "host": "127.0.0.1",
35
+ "port": 3306,
36
+ "user": "root",
37
+ "password": "test",
38
+ "charset": "utf8mb4_general_ci",
39
+ "supportBigNumbers": true,
40
+ "database": "test"
41
+ }
42
+ EOF
43
+ - run: npm test
package/README.md CHANGED
@@ -1,2 +1,4 @@
1
+ [![Build Status](https://github.com/larvit/larvitcms/actions/workflows/actions.yml/badge.svg)](https://github.com/larvit/larvitcms/actions)
2
+
1
3
  # larvitcms
2
4
  Very simple and basic CMS backend and admin page
package/cms.js CHANGED
@@ -1,25 +1,21 @@
1
1
  /* eslint-disable no-tabs */
2
2
  'use strict';
3
3
 
4
- const topLogPrefix = 'larvitcms: ./cms.js: ';
5
- const Intercom = require('larvitamintercom');
6
4
  const DataWriter = require(__dirname + '/dataWriter.js');
7
- const LUtils = require('larvitutils');
5
+ const { Utils, Log } = require('larvitutils');
6
+
7
+ const topLogPrefix = 'larvitcms: ./cms.js: ';
8
8
 
9
9
  class Cms {
10
10
  constructor(options) {
11
- const logPrefix = topLogPrefix + 'constructor() - ';
12
-
13
11
  this.options = options || {};
14
12
 
15
13
  if (!options.db) throw new Error('Missing required option "db"');
16
14
 
17
- if (!options.lUtils) options.lUtils = new LUtils();
15
+ if (!options.lUtils) options.lUtils = new Utils();
18
16
 
19
17
  if (!this.options.log) {
20
- const lUtils = new LUtils();
21
-
22
- this.options.log = new lUtils.Log();
18
+ this.options.log = new Log();
23
19
  }
24
20
 
25
21
  this.log = this.options.log;
@@ -28,44 +24,17 @@ class Cms {
28
24
  this[key] = this.options[key];
29
25
  }
30
26
 
31
- if (!this.exchangeName) {
32
- this.exchangeName = 'larvitcms';
33
- }
34
-
35
- if (!this.mode) {
36
- this.log.info(logPrefix + 'No "mode" option given, defaulting to "noSync"');
37
- this.mode = 'noSync';
38
- } else if (['noSync', 'master', 'slave'].indexOf(this.mode) === -1) {
39
- const err = new Error('Invalid "mode" option given: "' + this.mode + '"');
40
-
41
- this.log.error(logPrefix + err.message);
42
- throw err;
43
- }
44
-
45
- if (!this.intercom) {
46
- this.log.info(logPrefix + 'No "intercom" option given, defaulting to "loopback interface"');
47
- this.intercom = new Intercom('loopback interface');
48
- }
49
-
50
27
  this.dataWriter = new DataWriter({
51
- exchangeName: this.exchangeName,
52
- intercom: this.intercom,
53
- mode: this.mode,
54
28
  log: this.log,
55
29
  db: this.db,
56
- amsync_host: this.options.amsync_host || null,
57
- amsync_minPort: this.options.amsync_minPort || null,
58
- amsync_maxPort: this.options.amsync_maxPort || null
59
- }, err => {
60
- if (err) this.log.error(logPrefix + 'Failed to initialize dataWriter:' + err.message);
61
30
  });
62
31
  };
63
32
 
64
- ready(cb) {
65
- this.dataWriter.ready(cb);
33
+ async runDbMigrations() {
34
+ await this.dataWriter.runDbMigrations();
66
35
  }
67
36
 
68
- getPages(options, cb) {
37
+ async getPages(options) {
69
38
  const logPrefix = topLogPrefix + 'getPages() - ';
70
39
  const tmpPages = {};
71
40
  const dbFields = [];
@@ -73,10 +42,7 @@ class Cms {
73
42
 
74
43
  let sql;
75
44
 
76
- if (typeof options === 'function') {
77
- cb = options;
78
- options = {};
79
- }
45
+ options = options || {};
80
46
 
81
47
  this.log.debug(logPrefix + 'Called with options: "' + JSON.stringify(options) + '"');
82
48
 
@@ -142,10 +108,8 @@ class Cms {
142
108
 
143
109
  if (buffer === false) {
144
110
  const e = new Error('Invalid page uuid supplied');
145
-
146
111
  log.warn(logPrefix + e.message);
147
-
148
- return cb(e);
112
+ throw e;
149
113
  }
150
114
 
151
115
  sql += '?,';
@@ -171,175 +135,112 @@ class Cms {
171
135
  }
172
136
  }
173
137
 
174
- this.db.query(sql, dbFields, (err, rows) => {
175
- if (err) return cb(err);
176
-
177
- for (let i = 0; rows[i] !== undefined; i++) {
178
- const uuid = this.lUtils.formatUuid(rows[i].uuid);
138
+ const { rows } = await this.db.query(sql, dbFields);
139
+ for (let i = 0; rows[i] !== undefined; i++) {
140
+ const uuid = this.lUtils.formatUuid(rows[i].uuid);
179
141
 
180
- if (tmpPages[uuid] === undefined) {
181
- tmpPages[uuid] = {
182
- uuid: uuid,
183
- name: rows[i].name,
184
- published: Boolean(rows[i].published),
185
- template: rows[i].template,
186
- langs: {}
187
- };
188
- }
189
-
190
- tmpPages[uuid].langs[rows[i].lang] = {
191
- htmlTitle: rows[i].htmlTitle,
192
- body1: rows[i].body1,
193
- body2: rows[i].body2,
194
- body3: rows[i].body3,
195
- body4: rows[i].body4,
196
- body5: rows[i].body5,
197
- slug: rows[i].slug
142
+ if (tmpPages[uuid] === undefined) {
143
+ tmpPages[uuid] = {
144
+ uuid: uuid,
145
+ name: rows[i].name,
146
+ published: Boolean(rows[i].published),
147
+ template: rows[i].template,
148
+ langs: {},
198
149
  };
199
150
  }
200
151
 
201
- for (const pageUuid in tmpPages) {
202
- pages.push(tmpPages[pageUuid]);
203
- }
152
+ tmpPages[uuid].langs[rows[i].lang] = {
153
+ htmlTitle: rows[i].htmlTitle,
154
+ body1: rows[i].body1,
155
+ body2: rows[i].body2,
156
+ body3: rows[i].body3,
157
+ body4: rows[i].body4,
158
+ body5: rows[i].body5,
159
+ slug: rows[i].slug,
160
+ };
161
+ }
204
162
 
205
- cb(null, pages);
206
- });
163
+ for (const pageUuid in tmpPages) {
164
+ pages.push(tmpPages[pageUuid]);
165
+ }
166
+
167
+ return pages;
207
168
  };
208
169
 
209
- getSnippets(options, cb) {
210
- this.ready(() => {
211
- const dbFields = [];
212
- let sql;
170
+ async getSnippets(options) {
171
+ options = options || {};
213
172
 
214
- if (typeof options === 'function') {
215
- cb = options;
216
- options = {};
217
- }
173
+ if (options.onlyNames) {
174
+ const { rows } = await this.db.query('SELECT DISTINCT name FROM cms_snippets ORDER BY name;');
175
+ return rows;
176
+ }
218
177
 
219
- if (options.onlyNames) {
220
- sql = 'SELECT DISTINCT name FROM cms_snippets ORDER BY name;';
221
- this.db.query(sql, cb);
178
+ const dbFields = [];
179
+ let sql = 'SELECT * FROM cms_snippets\n';
180
+ sql += 'WHERE 1 + 1\n';
222
181
 
223
- return;
182
+ if (options.names !== undefined) {
183
+ if (typeof options.names === 'string') {
184
+ options.names = [options.names];
224
185
  }
225
186
 
226
- sql = 'SELECT * FROM cms_snippets\n';
227
- sql += 'WHERE 1 + 1\n';
228
-
229
- if (options.names !== undefined) {
230
- if (typeof options.names === 'string') {
231
- options.names = [options.names];
232
- }
233
-
234
- if (options.names.length === 0) {
235
- options.names = [''];
236
- }
237
-
238
- sql += ' AND name IN (';
239
-
240
- for (let i = 0; options.names[i] !== undefined; i++) {
241
- sql += '?,';
242
- dbFields.push(options.names[i]);
243
- }
244
-
245
- sql = sql.substring(0, sql.length - 1) + ')\n';
187
+ if (options.names.length === 0) {
188
+ options.names = [''];
246
189
  }
247
190
 
248
- sql += 'ORDER BY name, lang';
249
-
250
- this.db.query(sql, dbFields, (err, rows) => {
251
- const snippets = [];
191
+ sql += ' AND name IN (';
252
192
 
253
- let snippet;
254
- let prevName;
193
+ for (let i = 0; options.names[i] !== undefined; i++) {
194
+ sql += '?,';
195
+ dbFields.push(options.names[i]);
196
+ }
255
197
 
256
- if (err) return cb(err);
198
+ sql = sql.substring(0, sql.length - 1) + ')\n';
199
+ }
257
200
 
258
- for (let i = 0; rows[i] !== undefined; i++) {
259
- if (prevName !== rows[i].name) {
260
- if (snippet) {
261
- snippets.push(snippet);
262
- }
201
+ sql += 'ORDER BY name, lang';
263
202
 
264
- snippet = {name: rows[i].name, langs: {}};
265
- }
203
+ const { rows } = await this.db.query(sql, dbFields);
204
+ const snippets = [];
266
205
 
267
- prevName = rows[i].name;
268
- snippet.langs[rows[i].lang] = rows[i].body;
269
- }
206
+ let snippet;
207
+ let prevName;
270
208
 
271
- // Add the last one
209
+ for (let i = 0; rows[i] !== undefined; i++) {
210
+ if (prevName !== rows[i].name) {
272
211
  if (snippet) {
273
212
  snippets.push(snippet);
274
213
  }
275
214
 
276
- cb(null, snippets);
277
- });
278
- });
279
- }
280
-
281
- rmPage(uuid, cb) {
282
- const options = {exchange: this.exchangeName};
283
- const message = {};
284
-
285
- message.action = 'rmPage';
286
- message.params = {};
215
+ snippet = {name: rows[i].name, langs: {}};
216
+ }
287
217
 
288
- message.params.data = {uuid: uuid};
218
+ prevName = rows[i].name;
219
+ snippet.langs[rows[i].lang] = rows[i].body;
220
+ }
289
221
 
290
- this.dataWriter.intercom.send(message, options, (err, msgUuid) => {
291
- if (err) return cb(err);
222
+ // Add the last one
223
+ if (snippet) {
224
+ snippets.push(snippet);
225
+ }
292
226
 
293
- DataWriter.emitter.once(msgUuid, cb);
294
- });
227
+ return snippets;
295
228
  }
296
229
 
297
- rmSnippet(name, cb) {
298
- const options = {exchange: this.exchangeName};
299
- const message = {};
300
-
301
- message.action = 'rmSnippet';
302
- message.params = {};
303
-
304
- message.params.data = {name: name};
305
-
306
- this.dataWriter.intercom.send(message, options, (err, msgUuid) => {
307
- if (err) return cb(err);
308
-
309
- DataWriter.emitter.once(msgUuid, cb);
310
- });
230
+ async rmPage(uuid) {
231
+ await this.dataWriter.rmPage(uuid);
311
232
  }
312
233
 
313
- savePage(data, cb) {
314
- const options = {exchange: this.exchangeName};
315
- const message = {};
316
-
317
- message.action = 'savePage';
318
- message.params = {};
319
-
320
- message.params.data = data;
321
-
322
- this.dataWriter.intercom.send(message, options, (err, msgUuid) => {
323
- if (err) return cb(err);
234
+ async rmSnippet(name) {
235
+ await this.dataWriter.rmSnippet(name);
236
+ }
324
237
 
325
- DataWriter.emitter.once(msgUuid, cb);
326
- });
238
+ async savePage(data) {
239
+ await this.dataWriter.savePage(data);
327
240
  };
328
241
 
329
- saveSnippet(data, cb) {
330
- const options = {exchange: this.exchangeName};
331
- const message = {};
332
-
333
- message.action = 'saveSnippet';
334
- message.params = {};
335
-
336
- message.params.data = data;
337
-
338
- this.dataWriter.intercom.send(message, options, (err, msgUuid) => {
339
- if (err) return cb(err);
340
-
341
- DataWriter.emitter.once(msgUuid, cb);
342
- });
242
+ async saveSnippet(data) {
243
+ await this.dataWriter.saveSnippet(data);
343
244
  }
344
245
  }
345
246