From a93151c8e9a35a03326cdc9a2fcc8ed3aa7e5866 Mon Sep 17 00:00:00 2001 From: mkhorin Date: Thu, 2 Mar 2023 08:27:21 +1000 Subject: [PATCH] Update 3.5.1 --- HISTORY.md | 12 ++++---- base/Base.js | 5 ++-- base/Controller.js | 10 +++++-- base/FileMap.js | 12 +++++--- base/Module.js | 6 ++-- behavior/DataHistoryBehavior.js | 3 +- behavior/SortOrderBehavior.js | 9 ++++-- cache/DatabaseCache.js | 5 +++- data/Pagination.js | 7 +++-- db/ActiveLinker.js | 23 +++++++++------ db/ActiveQuery.js | 7 +++-- db/ActiveRecord.js | 22 +++++++++----- db/Expression.js | 3 +- db/MongoDatabase.js | 14 ++++++--- filter/AccessControl.js | 4 ++- filter/AccessRule.js | 6 ++-- helper/ArrayHelper.js | 2 +- helper/AsyncHelper.js | 37 ++++++++++++++++-------- helper/PromiseHelper.js | 3 +- helper/SecurityHelper.js | 2 +- helper/SystemHelper.js | 2 +- i18n/Formatter.js | 4 ++- i18n/I18n.js | 5 ++-- i18n/MessageSource.js | 10 +++++-- log/ActionProfiler.js | 3 +- log/FileLogStore.js | 9 ++++-- package.json | 8 +++--- scheduler/Task.js | 16 ++++++----- security/Auth.js | 12 +++++--- security/captcha/CaptchaAction.js | 4 ++- security/captcha/CaptchaValidator.js | 3 +- security/rateLimit/RateLimit.js | 15 ++++++---- security/rbac/Item.js | 18 ++++++++---- validator/EachValidator.js | 3 +- validator/EmailValidator.js | 3 +- validator/FileValidator.js | 5 +++- validator/NumberValidator.js | 3 +- validator/UniqueValidator.js | 4 +-- validator/UrlValidator.js | 3 +- view/ActionView.js | 2 +- view/LocaleFileMap.js | 12 +++++--- view/Theme.js | 22 ++++++++------ view/ThemeSet.js | 7 +++-- view/Widget.js | 2 ++ web/Response.js | 3 +- web/Router.js | 43 +++++++++++++++++----------- web/packer/FilePack.js | 3 +- web/session/DatabaseSessionStore.js | 3 +- web/session/SessionStore.js | 12 ++++---- 49 files changed, 279 insertions(+), 152 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 463c164..9d90375 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,8 +2,8 @@ * db/MongoDatabase - remove deprecated reindexing -* upgrade dependencies - +* upgrade dependencies + ## 3.4.0 * helper/CommonHelper @@ -15,14 +15,14 @@ * validator/Validator - fix checking of active scenarios * web/asset/AssetBundle - - fix style asset render - + - fix style asset render + ## 3.3.0 * web/session - refactor session stores -* upgrade dependencies - +* upgrade dependencies + ## 3.2.0 * base/Configuration diff --git a/base/Base.js b/base/Base.js index e1dcaa8..6486089 100644 --- a/base/Base.js +++ b/base/Base.js @@ -10,8 +10,9 @@ module.exports = class Base { static init (nodeModule) { if (nodeModule) { - ClassHelper.defineClassProperty(this, 'CLASS_FILE', nodeModule.filename); - ClassHelper.defineClassProperty(this, 'CLASS_DIRECTORY', path.dirname(nodeModule.filename)); + const file = nodeModule.filename; + ClassHelper.defineClassProperty(this, 'CLASS_FILE', file); + ClassHelper.defineClassProperty(this, 'CLASS_DIRECTORY', path.dirname(file)); } ClassHelper.defineConstantClassProperties(this); return this; diff --git a/base/Controller.js b/base/Controller.js index b4ad64f..1a79cc3 100644 --- a/base/Controller.js +++ b/base/Controller.js @@ -64,7 +64,10 @@ module.exports = class Controller extends Base { static getModelClass () { if (!this.hasOwnProperty('_MODEL_CLASS')) { - const closest = FileHelper.getClosestDirectory(this.CONTROLLER_DIRECTORY, this.CLASS_DIRECTORY); + const closest = FileHelper.getClosestDirectory( + this.CONTROLLER_DIRECTORY, + this.CLASS_DIRECTORY + ); const nested = this.getNestedDirectory(); const className = this.getModelClassName(); const dir = path.join(this.MODEL_DIRECTORY, nested, className); @@ -90,7 +93,10 @@ module.exports = class Controller extends Base { static getNestedDirectory () { if (!this.hasOwnProperty('_NESTED_DIRECTORY')) { - this._NESTED_DIRECTORY = FileHelper.getRelativePathByDirectory(this.CONTROLLER_DIRECTORY, this.CLASS_DIRECTORY); + this._NESTED_DIRECTORY = FileHelper.getRelativePathByDirectory( + this.CONTROLLER_DIRECTORY, + this.CLASS_DIRECTORY + ); } return this._NESTED_DIRECTORY; } diff --git a/base/FileMap.js b/base/FileMap.js index 29952c4..11b863a 100644 --- a/base/FileMap.js +++ b/base/FileMap.js @@ -41,12 +41,15 @@ module.exports = class FileMap extends Base { } indexDirectoryFiles (dir) { - for (const name of fs.readdirSync(dir)) { + const names = fs.readdirSync(dir); + for (const name of names) { const file = path.join(dir, name); - if (fs.lstatSync(file).isDirectory()) { + const stat = fs.lstatSync(file); + if (stat.isDirectory()) { this.indexDirectoryFiles(file); } else { - this._files[this.getKey(file)] = file; + const key = this.getKey(file); + this._files[key] = file; } } } @@ -54,7 +57,8 @@ module.exports = class FileMap extends Base { getKey (file) { const relative = file.substring(this.directory.length + 1); const parts = relative.split(path.sep); - parts.push(FileHelper.trimExtension(parts.pop())); + const name = parts.pop(); + parts.push(FileHelper.trimExtension(name)); return parts.join('/'); // normalize separator } diff --git a/base/Module.js b/base/Module.js index 45934c2..3dc74a7 100644 --- a/base/Module.js +++ b/base/Module.js @@ -289,11 +289,13 @@ module.exports = class Module extends Base { } beforeAction (action) { - return this.trigger(this.EVENT_BEFORE_ACTION, new ActionEvent(action)); + const event = new ActionEvent(action); + return this.trigger(this.EVENT_BEFORE_ACTION, event); } afterAction (action) { - return this.trigger(this.EVENT_AFTER_ACTION, new ActionEvent(action)); + const event = new ActionEvent(action); + return this.trigger(this.EVENT_AFTER_ACTION, event); } // INIT diff --git a/behavior/DataHistoryBehavior.js b/behavior/DataHistoryBehavior.js index 9ebbd05..05e36ab 100644 --- a/behavior/DataHistoryBehavior.js +++ b/behavior/DataHistoryBehavior.js @@ -26,7 +26,8 @@ module.exports = class DataHistoryBehavior extends Base { } async beforeUpdate () { - for (const name of this.getAttrNames()) { + const names = this.getAttrNames(); + for (const name of names) { if (this.owner.isAttrChanged(name)) { await this.createHistory(name); } diff --git a/behavior/SortOrderBehavior.js b/behavior/SortOrderBehavior.js index 4ef363c..1dec1e1 100644 --- a/behavior/SortOrderBehavior.js +++ b/behavior/SortOrderBehavior.js @@ -19,8 +19,10 @@ module.exports = class SortOrderBehavior extends Base { } async beforeInsert () { - if (CommonHelper.isEmpty(this.owner.get(this.orderAttr))) { - this.owner.set(this.orderAttr, await this.getNextNumber()); + const order = this.owner.get(this.orderAttr); + if (CommonHelper.isEmpty(order)) { + const next = await this.getNextNumber(); + this.owner.set(this.orderAttr, next); } } @@ -29,7 +31,8 @@ module.exports = class SortOrderBehavior extends Base { if (typeof this.filter === 'function') { this.filter(query, this.owner); } else if (typeof this.filter === 'string') { - query.and({[this.filter]: this.owner.get(this.filter)}); + const value = this.owner.get(this.filter); + query.and({[this.filter]: value}); } const direction = this.step > 0 ? -1 : 1; const order = {[this.orderAttr]: direction}; diff --git a/cache/DatabaseCache.js b/cache/DatabaseCache.js index 587ae97..dc13ece 100644 --- a/cache/DatabaseCache.js +++ b/cache/DatabaseCache.js @@ -25,7 +25,10 @@ module.exports = class DatabaseCache extends Base { const query = this.getQuery().and({key}); const data = await query.one(); if (data) { - if (!data.expiredAt || data.expiredAt > this.constructor.getNow()) { + if (!data.expiredAt) { + return data.value; + } + if (data.expiredAt > this.constructor.getNow()) { return data.value; } } diff --git a/data/Pagination.js b/data/Pagination.js index 4e8e952..a6e6901 100644 --- a/data/Pagination.js +++ b/data/Pagination.js @@ -43,7 +43,8 @@ module.exports = class Pagination extends Base { } this.setPageSize(this.pageSize); if (this.page === null) { - this.page = parseInt(this.getQueryParam(this.pageParam, 1)) - 1; + const page = this.getQueryParam(this.pageParam, 1); + this.page = parseInt(page) - 1; } this.setPage(this.page); } @@ -128,7 +129,9 @@ module.exports = class Pagination extends Base { } else { delete params[this.pageParam]; } - pageSize = pageSize || this.pageSize; + if (!pageSize) { + pageSize = this.pageSize; + } if (pageSize !== this.defaultPageSize) { params[this.pageSizeParam] = pageSize; } else { diff --git a/db/ActiveLinker.js b/db/ActiveLinker.js index 4e7f035..61d09d7 100644 --- a/db/ActiveLinker.js +++ b/db/ActiveLinker.js @@ -93,7 +93,9 @@ module.exports = class ActiveLinker extends Base { async unlinkAll (name, deletion) { const relation = this.owner.getRelation(name); if (relation) { - const method = relation.isOuterLink() ? 'unlinkViaAll' : 'unlinkInternalAll'; + const method = relation.isOuterLink() + ? 'unlinkViaAll' + : 'unlinkInternalAll'; await this[method](relation, deletion); this.owner.unsetRelated(name); } @@ -115,7 +117,8 @@ module.exports = class ActiveLinker extends Base { deletion ? await db.delete(via.getTable(), condition) : await db.update(via.getTable(), condition, nulls); } else if (deletion) { - for (const model of await via.model.find(condition).all()) { + const models = await via.model.find(condition).all(); + for (const model of models) { await model.delete(); } } else { @@ -125,16 +128,20 @@ module.exports = class ActiveLinker extends Base { async unlinkInternalAll (relation) { // relation via array valued attribute - if (Array.isArray(this.owner.get(relation.linkKey))) { + const link = this.owner.get(relation.linkKey); + if (Array.isArray(link)) { return this.owner.directUpdate({[relation.linkKey]: []}); } - let condition = {[relation.refKey]: this.owner.get(relation.linkKey)}; + let condition = {[relation.refKey]: link}; if (relation.getWhere()) { condition = ['and', condition, relation.getWhere()]; } - relation.getViaArray() - ? await relation.model.getDb().updateAllPull(relation.model.getTable(), {}, condition) - : await relation.model.find(condition).updateAll({[relation.refKey]: null}); + if (relation.getViaArray()) { + const table = relation.model.getTable(); + await relation.model.getDb().updateAllPull(table, {}, condition); + } else { + await relation.model.find(condition).updateAll({[relation.refKey]: null}); + } } unsetUnlinked (name, model, relation) { @@ -144,7 +151,7 @@ module.exports = class ActiveLinker extends Base { const models = this.owner.getRelated(name); if (Array.isArray(models)) { const id = model.getId(); - const result = models.filter(target => !CommonHelper.isEqual(id, target.getId())); + const result = models.filter(m => !CommonHelper.isEqual(id, m.getId())); this.owner.populateRelation(name, result); } } diff --git a/db/ActiveQuery.js b/db/ActiveQuery.js index 936c5ac..d0aeb2b 100644 --- a/db/ActiveQuery.js +++ b/db/ActiveQuery.js @@ -272,9 +272,10 @@ module.exports = class ActiveQuery extends Base { return true; } const link = this.primaryModel.get(this.linkKey); - return link !== null - && link !== undefined - && (!Array.isArray(link) || link.length); + if (link === null || link === undefined) { + return false; + } + return !Array.isArray(link) || link.length; } // POPULATE diff --git a/db/ActiveRecord.js b/db/ActiveRecord.js index 53c2294..d735148 100644 --- a/db/ActiveRecord.js +++ b/db/ActiveRecord.js @@ -202,7 +202,9 @@ module.exports = class ActiveRecord extends Base { async insert () { await this.beforeSave(true); - this.set(this.PK, await this.createQuery().insert(this.filterAttrs())); + const data = this.filterAttrs(); + const id = await this.createQuery().insert(data); + this.set(this.PK, id); this._isNew = false; await this.afterSave(true); this.assignOldAttrs(); @@ -210,7 +212,8 @@ module.exports = class ActiveRecord extends Base { async update () { await this.beforeSave(false); - await this.findSelf().update(this.filterAttrs()); + const data = this.filterAttrs(); + await this.findSelf().update(data); await this.afterSave(false); this.assignOldAttrs(); } @@ -218,7 +221,8 @@ module.exports = class ActiveRecord extends Base { // skip before and after save triggers async directUpdate (data) { this.assign(data); - await this.findSelf().update(this.filterAttrs()); + data = this.filterAttrs(); + await this.findSelf().update(data); this.assignOldAttrs(); } @@ -244,7 +248,8 @@ module.exports = class ActiveRecord extends Base { static async resolveRelation (name, models) { const relations = []; for (const model of models) { - relations.push(await model.resolveRelation(name)); + const result = await model.resolveRelation(name); + relations.push(result); } return relations; } @@ -252,7 +257,8 @@ module.exports = class ActiveRecord extends Base { static async resolveRelations (names, models) { const relations = []; for (const model of models) { - relations.push(await model.resolveRelations(names)); + const result = await model.resolveRelations(names); + relations.push(result); } return relations; } @@ -372,7 +378,8 @@ module.exports = class ActiveRecord extends Base { const models = []; for (const model of result) { if (typeof model?.resolveRelation === 'function') { - models.push(await model.resolveRelation(nestedName)); + const items = await model.resolveRelation(nestedName); + models.push(items); } } return ArrayHelper.concat(models); @@ -397,7 +404,8 @@ module.exports = class ActiveRecord extends Base { async resolveRelations (names) { const result = []; for (const name of names) { - result.push(await this.resolveRelation(name)); + const data = await this.resolveRelation(name); + result.push(data); } return result; } diff --git a/db/Expression.js b/db/Expression.js index 5d2f135..6a51aaa 100644 --- a/db/Expression.js +++ b/db/Expression.js @@ -16,7 +16,8 @@ module.exports = class Expression { if (this.params) { for (const key of Object.keys(this.params)) { const regex = new RegExp(`:${key}`, 'g'); - this._value = this._value.replace(regex, db.escape(this.params[key])); + const value = db.escape(this.params[key]); + this._value = this._value.replace(regex, value); } } } diff --git a/db/MongoDatabase.js b/db/MongoDatabase.js index 6dad639..e16154b 100644 --- a/db/MongoDatabase.js +++ b/db/MongoDatabase.js @@ -39,7 +39,8 @@ module.exports = class MongoDatabase extends Base { } async isTableExists (name) { - for (const {collectionName} of await this._connection.collections()) { + const collections = await this._connection.collections(); + for (const {collectionName} of collections) { if (name === collectionName) { return true; } @@ -48,7 +49,8 @@ module.exports = class MongoDatabase extends Base { async getTableNames () { const names = []; - for (const {collectionName} of await this._connection.collections()) { + const collections = await this._connection.collections(); + for (const {collectionName} of collections) { names.push(collectionName); } return names; @@ -100,7 +102,10 @@ module.exports = class MongoDatabase extends Base { upsert (table, query, data, options) { this.traceCommand('upsert', {table, query, data}); - return this.getTable(table).updateOne(query, {$set: data}, {upsert: true, ...options}); + return this.getTable(table).updateOne(query, {$set: data}, { + upsert: true, + ...options + }); } update (table, query, data, options) { @@ -147,7 +152,8 @@ module.exports = class MongoDatabase extends Base { async dropAll () { this.traceCommand('dropAll'); - for (const name of await this.getTableNames()) { + const names = await this.getTableNames(); + for (const name of names) { await this.drop(name); } } diff --git a/filter/AccessControl.js b/filter/AccessControl.js index e69ce6e..d195560 100644 --- a/filter/AccessControl.js +++ b/filter/AccessControl.js @@ -29,7 +29,9 @@ module.exports = class AccessControl extends Base { createRules () { const rules = []; for (const config of this.rules) { - config.Class = config.Class || this.AccessRule; + if (!config.Class) { + config.Class = this.AccessRule; + } rules.push(this.spawn(config)); } return rules; diff --git a/filter/AccessRule.js b/filter/AccessRule.js index edad9ba..18f0fe0 100644 --- a/filter/AccessRule.js +++ b/filter/AccessRule.js @@ -30,12 +30,14 @@ module.exports = class AccessRule extends Base { } } if (this.methods) { - if (!this.methods.includes(action.controller.req.method?.toLowerCase())) { + const name = action.controller.req.method?.toLowerCase(); + if (!this.methods.includes(name)) { return; } } if (this.controllers) { - if (!this.controllers.includes(action.controller.getBaseName())) { + const name = action.controller.getBaseName(); + if (!this.controllers.includes(name)) { return; } } diff --git a/helper/ArrayHelper.js b/helper/ArrayHelper.js index ad7ea10..a3a609e 100644 --- a/helper/ArrayHelper.js +++ b/helper/ArrayHelper.js @@ -52,7 +52,7 @@ module.exports = class ArrayHelper { static hasDiff (targets, sources, indexOf) { for (const source of sources) { - const index = indexOf + const index = indexOf ? indexOf(source, targets) : targets.indexOf(source); if (index === -1) { diff --git a/helper/AsyncHelper.js b/helper/AsyncHelper.js index 2f59f09..e9ce85a 100644 --- a/helper/AsyncHelper.js +++ b/helper/AsyncHelper.js @@ -16,14 +16,16 @@ module.exports = class AsyncHelper { if (!keys.length) { return callback(null, result); } - (new this({items, callback, keys, result})).series(); + const instance = new this({items, callback, keys, result}); + instance.series(); } static eachSeries (items, handler, callback) { if (!Array.isArray(items) || !items.length) { return callback(); } - (new this({items, handler, callback})).eachSeries(); + const instance = new this({items, handler, callback}); + instance.eachSeries(); } static eachOfSeries (items, handler, callback) { @@ -34,7 +36,8 @@ module.exports = class AsyncHelper { if (!keys.length) { return callback(); } - (new this({items, handler, callback, keys})).eachOfSeries(); + const instance = new this({items, handler, callback, keys}); + instance.eachOfSeries(); } static mapSeries (items, handler, callback) { @@ -42,7 +45,8 @@ module.exports = class AsyncHelper { if (!Array.isArray(items) || !items.length) { return callback(null, result); } - (new this({items, handler, callback, result})).mapSeries(); + const instance = new this({items, handler, callback, result}); + instance.mapSeries(); } static filterSeries (items, handler, callback) { @@ -50,14 +54,16 @@ module.exports = class AsyncHelper { if (!Array.isArray(items) || !items.length) { return callback(null, result); } - (new this({items, handler, callback, result})).filterSeries(); + const instance = new this({items, handler, callback, result}); + instance.filterSeries(); } static someSeries (items, handler, callback) { if (!Array.isArray(items) || !items.length) { return callback(null, false); } - (new this({items, handler, callback})).someSeries(); + const instance = new this({items, handler, callback}); + instance.someSeries(); } static mapValuesSeries (items, handler, callback) { @@ -69,14 +75,16 @@ module.exports = class AsyncHelper { if (!keys.length) { return callback(null, result); } - (new this({items, handler, callback, keys, result})).mapValuesSeries(); + const instance = new this({items, handler, callback, keys, result}); + instance.mapValuesSeries(); } static waterfall (items, callback) { if (!Array.isArray(items) || !items.length) { return callback(); } - (new this({items, callback})).waterfall(); + const instance = new this({items, callback}); + instance.waterfall(); } // PARALLEL @@ -85,7 +93,8 @@ module.exports = class AsyncHelper { if (!Array.isArray(items) || !items.length) { return callback(); } - (new this({items, handler, callback, counter: 0})).each(); + const instance = new this({items, handler, callback, counter: 0}); + instance.each(); } static parallel (items, callback) { @@ -97,7 +106,8 @@ module.exports = class AsyncHelper { if (!keys.length) { return callback(null, result); } - (new this({items, callback, keys, result, counter: 0})).each(); + const instance = new this({items, callback, keys, result, counter: 0}); + instance.each(); } // METHOD @@ -217,8 +227,11 @@ module.exports = class AsyncHelper { each () { const process = err => { - if (err || ++this.counter === this.items.length) { - this.callback(err); + if (err) { + return this.callback(err); + } + if (++this.counter === this.items.length) { + return this.callback(); } }; for (const item of this.items) { diff --git a/helper/PromiseHelper.js b/helper/PromiseHelper.js index 457732c..d1c1174 100644 --- a/helper/PromiseHelper.js +++ b/helper/PromiseHelper.js @@ -55,7 +55,8 @@ module.exports = class PromiseHelper { const result = []; if (Array.isArray(items)) { for (const item of items) { - result.push(await handler.call(context, item)); + const value = await handler.call(context, item); + result.push(value); } } return result; diff --git a/helper/SecurityHelper.js b/helper/SecurityHelper.js index f4154fc..8b6344b 100644 --- a/helper/SecurityHelper.js +++ b/helper/SecurityHelper.js @@ -33,7 +33,7 @@ module.exports = class SecurityHelper { } static hashPassword (password) { - return !password ? '' : this.hashValue(password, this.createSalt()); + return password ? this.hashValue(password, this.createSalt()) : ''; } static hashValue (value, salt, method = DEFAULT_HASH_METHOD) { diff --git a/helper/SystemHelper.js b/helper/SystemHelper.js index bd47177..e5100dd 100644 --- a/helper/SystemHelper.js +++ b/helper/SystemHelper.js @@ -19,7 +19,7 @@ module.exports = class CommonHelper { const value = item === 'true' ? true : item === 'false' ? false : item; if (Array.isArray(result[key])) { result[key].push(value); - } else if (result.hasOwnProperty(key)) { + } else if (Object.prototype.hasOwnProperty.call(result, key)) { result[key] = [result[key], value]; } else { result[key] = value; diff --git a/i18n/Formatter.js b/i18n/Formatter.js index 27b9413..20703c2 100644 --- a/i18n/Formatter.js +++ b/i18n/Formatter.js @@ -177,7 +177,9 @@ module.exports = class Formatter extends Base { } asIso (value) { - return value ? this.getMoment(value).toISOString() : this.asRaw(value); + return value + ? this.getMoment(value).toISOString() + : this.asRaw(value); } asClientDate (value, params = {}) { diff --git a/i18n/I18n.js b/i18n/I18n.js index 4a92597..5a33052 100644 --- a/i18n/I18n.js +++ b/i18n/I18n.js @@ -91,7 +91,8 @@ module.exports = class I18n extends Base { resolveSourceParents () { for (const name of Object.keys(this.sources)) { - this.sources[name].setParent(this.resolveSourceParent(name)); + const parent = this.resolveSourceParent(name); + this.sources[name].setParent(parent); if (ObjectHelper.hasCircularLinks(this.sources[name], 'parent')) { throw new Error(`Circular source parents: ${name}`); } @@ -110,7 +111,7 @@ module.exports = class I18n extends Base { getSourceParent (name) { return this.parent - ? (this.parent.getSource(name) || this.parent.getSourceParent(name)) + ? this.parent.getSource(name) || this.parent.getSourceParent(name) : null; } diff --git a/i18n/MessageSource.js b/i18n/MessageSource.js index 582843c..36b0411 100644 --- a/i18n/MessageSource.js +++ b/i18n/MessageSource.js @@ -26,9 +26,13 @@ module.exports = class MessageSource extends Base { setParent (parent) { this.parent = parent; - this.forceTranslationParent = parent - ? (parent.forceTranslation ? parent : parent.forceTranslationParent) - : null; + if (parent) { + this.forceTranslationParent = parent.forceTranslation + ? parent + : parent.forceTranslationParent + } else { + this.forceTranslationParent = null; + } } translate (message, language) { diff --git a/log/ActionProfiler.js b/log/ActionProfiler.js index 9bbedfe..4ca88fa 100644 --- a/log/ActionProfiler.js +++ b/log/ActionProfiler.js @@ -37,7 +37,8 @@ module.exports = class ActionProfiler extends Base { const controller = event.action.controller; const time = Date.now() - controller.res.locals.startActionTimeProfiler; if (time >= this.threshold) { - this.logger.log(this.level, this.formatTime(time, controller)); + const message = this.formatTime(time, controller); + this.logger.log(this.level, message); } } diff --git a/log/FileLogStore.js b/log/FileLogStore.js index 4764cc8..21c785a 100644 --- a/log/FileLogStore.js +++ b/log/FileLogStore.js @@ -119,7 +119,8 @@ module.exports = class FileLogStore extends Base { const files = await this.getSortedFiles(); await this.deleteExcessFiles(files); for (let i = files.length - 1; i >= 0; --i) { - await fs.promises.rename(files[i], this.getFile(i + 1)); + const file = this.getFile(i + 1); + await fs.promises.rename(files[i], file); } this.log('info', `Rotation done: ${this.name}`); } @@ -136,7 +137,8 @@ module.exports = class FileLogStore extends Base { async getSortedFiles () { const baseName = path.basename(this.file); const items = []; - for (let name of await fs.promises.readdir(this.basePath)) { + const names = await fs.promises.readdir(this.basePath); + for (let name of names) { if (name.indexOf(this.name) === 0 && name !== baseName) { const file = path.join(this.basePath, name); const stat = await fs.promises.stat(file); @@ -153,7 +155,8 @@ module.exports = class FileLogStore extends Base { async getFiles () { const items = []; - for (let name of await fs.promises.readdir(this.basePath)) { + const names = await fs.promises.readdir(this.basePath); + for (let name of names) { if (name.indexOf(this.name) === 0) { const file = path.join(this.basePath, name); const stat = await fs.promises.stat(file); diff --git a/package.json b/package.json index 2a563ba..695c4da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "areto", - "version": "3.5.0", + "version": "3.5.1", "description": "Adaptive Node.js MVC Framework", "author": { "name": "Maxim Khorin", @@ -16,13 +16,13 @@ "url": "https://github.com/mkhorin/areto.git" }, "dependencies": { - "body-parser": "~1.20.0", + "body-parser": "~1.20.2", "connect-flash": "~0.1.1", "cookie-parser": "~1.4.6", - "express": "~4.18.1", + "express": "~4.18.2", "express-session": "~1.17.2", "moment": "~2.29.4", - "mongodb": "~5.0.0", + "mongodb": "~5.1.0", "mysql": "~2.18.1", "path-to-regexp": "~6.2.0" }, diff --git a/scheduler/Task.js b/scheduler/Task.js index 6b52316..c651941 100644 --- a/scheduler/Task.js +++ b/scheduler/Task.js @@ -117,14 +117,14 @@ module.exports = class Task extends Base { } formatStartTime () { - let date = `${moment().format('YYYY-MM-DD')} ${this.startTime}`; + const date = `${moment().format('YYYY-MM-DD')} ${this.startTime}`; if (!DateHelper.isValid(date)) { return this.log('error', `Invalid start time: ${date}`); } - date = (new Date(date)).getTime(); - return date < Date.now() - ? date + this.DAY_PERIOD - : date; + const time = (new Date(date)).getTime(); + return time < Date.now() + ? time + this.DAY_PERIOD + : time; } refresh () { @@ -195,7 +195,8 @@ module.exports = class Task extends Base { } done (result) { - return this.trigger(this.EVENT_DONE, new Event({result})); + const event = new Event({result}); + return this.trigger(this.EVENT_DONE, event); } fail (error) { @@ -203,7 +204,8 @@ module.exports = class Task extends Base { this._nextDate = null; } this._lastError = error; - return this.trigger(this.EVENT_FAIL, new Event({error})); + const event = new Event({error}); + return this.trigger(this.EVENT_FAIL, event); } log (type, message, data) { diff --git a/security/Auth.js b/security/Auth.js index c0c24ec..b3385a1 100644 --- a/security/Auth.js +++ b/security/Auth.js @@ -80,22 +80,26 @@ module.exports = class Auth extends Base { beforeLogin (data) { // call await super.beforeLogin(data) if override it - return this.trigger(this.EVENT_BEFORE_LOGIN, new Event(data)); + const event = new Event(data); + return this.trigger(this.EVENT_BEFORE_LOGIN, event); } afterLogin (data) { // call await super.afterLogin(data) if override it - return this.trigger(this.EVENT_AFTER_LOGIN, new Event(data)); + const event = new Event(data); + return this.trigger(this.EVENT_AFTER_LOGIN, event); } beforeLogout (data) { // call await super.beforeLogout(data) if override it - return this.trigger(this.EVENT_BEFORE_LOGOUT, new Event(data)); + const event = new Event(data); + return this.trigger(this.EVENT_BEFORE_LOGOUT, event); } afterLogout (data) { // call await super.afterLogout(data) if override it - return this.trigger(this.EVENT_AFTER_LOGOUT, new Event(data)); + const event = new Event(data); + return this.trigger(this.EVENT_AFTER_LOGOUT, event); } // LOGIN diff --git a/security/captcha/CaptchaAction.js b/security/captcha/CaptchaAction.js index a1db6c8..4b6b256 100644 --- a/security/captcha/CaptchaAction.js +++ b/security/captcha/CaptchaAction.js @@ -78,7 +78,9 @@ module.exports = class Captcha extends Base { content += this.drawGrid(); } const sharp = require('sharp'); - const image = sharp(new Buffer(this.drawBack(content))); + const result = this.drawBack(content); + const buffer = new Buffer(result); + const image = sharp(buffer); if (this.median) { image.median(this.median); } diff --git a/security/captcha/CaptchaValidator.js b/security/captcha/CaptchaValidator.js index 0768380..c2bfaa0 100644 --- a/security/captcha/CaptchaValidator.js +++ b/security/captcha/CaptchaValidator.js @@ -24,7 +24,8 @@ module.exports = class CaptchaValidator extends Base { if (!(action instanceof CaptchaAction)) { throw new Error(`Captcha action not found in model.${this.captchaActionProperty}`); } - if (!action.validate(model.get(attr))) { + const value = model.get(attr); + if (!action.validate(value)) { this.addError(model, attr, this.getMessage()); } } diff --git a/security/rateLimit/RateLimit.js b/security/rateLimit/RateLimit.js index 127de5c..a1f7e20 100644 --- a/security/rateLimit/RateLimit.js +++ b/security/rateLimit/RateLimit.js @@ -43,7 +43,8 @@ module.exports = class RateLimit extends Base { } afterRateUpdate (model) { - return this.trigger(this.EVENT_AFTER_RATE_UPDATE, new Event({model})); + const event = new Event({model}); + return this.trigger(this.EVENT_AFTER_RATE_UPDATE, event); } getAttempts (type) { @@ -55,13 +56,17 @@ module.exports = class RateLimit extends Base { } getInternalParam (type, name) { - if (!this.types || !Object.prototype.hasOwnProperty.call(this.types, type)) { + if (!this.types) { + return this[name]; + } + if (!Object.prototype.hasOwnProperty.call(this.types, type)) { return this[name]; } type = this.types[type]; - return type && Object.prototype.hasOwnProperty.call(type, name) - ? type[name] - : this[name]; + if (type && Object.prototype.hasOwnProperty.call(type, name)) { + return type[name]; + } + return this[name]; } }; module.exports.init(); diff --git a/security/rbac/Item.js b/security/rbac/Item.js index 5ac0a30..adce05c 100644 --- a/security/rbac/Item.js +++ b/security/rbac/Item.js @@ -44,7 +44,8 @@ module.exports = class Item extends Base { if (!this.constructor.isType(this.data.type)) { return this.log('error', `Invalid type: ${this.data.type}`); } - const item = await this.store.findItemByName(this.name).one(); + const query = this.store.findItemByName(this.name); + const item = await query.one(); if (item) { return this.log('warn', 'Already exists'); } @@ -55,7 +56,8 @@ module.exports = class Item extends Base { ...relations }; ObjectHelper.deleteProperties(['children', 'parents'], data); - await this.store.findItem().insert(data); + const creationQuery = this.store.findItem(); + await creationQuery.insert(data); } async resolveRelations () { @@ -97,9 +99,11 @@ module.exports = class Item extends Base { } const child = await this.resolveRelatives('children'); const parent = this.data.itemId; - await this.store.findItemChild().and({child, parent}).delete(); + const deletionQuery = this.store.findItemChild().and({child, parent}); + await deletionQuery.delete(); const items = child.map(child => ({child, parent})); - await this.store.findItemChild().insert(items); + const creationQuery = this.store.findItemChild(); + await creationQuery.insert(items); this.data.children = child; } @@ -112,12 +116,14 @@ module.exports = class Item extends Base { const deletionQuery = this.store.findItemChild().and({child, parent}); await deletionQuery.delete(); const items = parent.map(parent => ({child, parent})); - await this.store.findItemChild().insert(items); + const creationQuery = this.store.findItemChild(); + await creationQuery.insert(items); this.data.parents = parent; } async resolveRelatives (key) { - const item = await this.store.findItemByName(this.name).one(); + const query = this.store.findItemByName(this.name); + const item = await query.one(); this.data.itemId = item ? item[this.store.key] : null; const names = this.data[key]; const items = await this.store.findItemByName(names).all(); diff --git a/validator/EachValidator.js b/validator/EachValidator.js index ecf3537..1f23d47 100644 --- a/validator/EachValidator.js +++ b/validator/EachValidator.js @@ -48,7 +48,8 @@ module.exports = class EachValidator extends Base { model.set(attr, filteredValues); for (const value of values) { if (!(Array.isArray(value) && validator.skipOnArray)) { - filteredValues.push(await validator.filter(value, attr, model)); + const result = await validator.filter(value, attr, model); + filteredValues.push(result); } } } diff --git a/validator/EmailValidator.js b/validator/EmailValidator.js index 68a5d1a..18742fb 100644 --- a/validator/EmailValidator.js +++ b/validator/EmailValidator.js @@ -23,7 +23,8 @@ module.exports = class EmailValidator extends Base { if (typeof value !== 'string' || value.length > this.maxLength) { return this.getMessage(); } - if (!(new RegExp(this.pattern)).test(value)) { + const regex = new RegExp(this.pattern); + if (!regex.test(value)) { return this.getMessage(); } } diff --git a/validator/FileValidator.js b/validator/FileValidator.js index c009d3f..93d3cae 100644 --- a/validator/FileValidator.js +++ b/validator/FileValidator.js @@ -66,9 +66,12 @@ module.exports = class FileValidator extends Base { return this.getTooBigMessage(); } if (Array.isArray(this.extensions)) { - if (!file.extension || !this.extensions.includes(file.extension.toLowerCase())) { + if (!file.extension) { return this.getWrongExtensionMessage(); } + if (!this.extensions.includes(file.extension.toLowerCase())) { + return this.getWrongExtensionMessage(); + } } if (Array.isArray(this.types)) { if (!file.type || !this.types.includes(file.type)) { diff --git a/validator/NumberValidator.js b/validator/NumberValidator.js index 10d5827..77c361a 100644 --- a/validator/NumberValidator.js +++ b/validator/NumberValidator.js @@ -44,7 +44,8 @@ module.exports = class NumberValidator extends Base { async validateAttr (attr, model) { await super.validateAttr(...arguments); if (!model.hasError()) { - model.set(attr, Number(model.get(attr))); + const value = model.get(attr); + model.set(attr, Number(value)); } } diff --git a/validator/UniqueValidator.js b/validator/UniqueValidator.js index fd5291d..dd9840a 100644 --- a/validator/UniqueValidator.js +++ b/validator/UniqueValidator.js @@ -14,8 +14,8 @@ module.exports = class UniqueValidator extends Base { async validateAttr (attr, model) { const targetClass = this.targetClass || model.constructor; const values = this.resolveValues(attr, model); - const query = this.createQuery(values, attr, model); - const ids = await query.limit(2).column(targetClass.PK); + const query = this.createQuery(values, attr, model).limit(2); + const ids = await query.column(targetClass.PK); if (this.checkExists(ids, model, targetClass)) { this.addError(model, attr, this.getMessage()); } diff --git a/validator/UrlValidator.js b/validator/UrlValidator.js index 9074315..fa7fc99 100644 --- a/validator/UrlValidator.js +++ b/validator/UrlValidator.js @@ -43,7 +43,8 @@ module.exports = class UrlValidator extends Base { let schemes = this.validSchemes.join('|'); pattern = pattern.replace('{schemes}', `(${schemes})`); } - if (!(new RegExp(pattern, 'i')).test(value)) { + const regex = new RegExp(pattern, 'i'); + if (!regex.test(value)) { return this.getMessage(); } } diff --git a/view/ActionView.js b/view/ActionView.js index 4eec0e4..2cd3c60 100644 --- a/view/ActionView.js +++ b/view/ActionView.js @@ -150,7 +150,7 @@ module.exports = class ActionView extends Base { // WIDGET placeWidget (name, params) { - if (!this.widgets.hasOwnProperty(name)) { + if (!Object.prototype.hasOwnProperty.call(this.widgets, name)) { this.widgets[name] = params || {}; } return `#{${name}}`; diff --git a/view/LocaleFileMap.js b/view/LocaleFileMap.js index 73b3735..34ea06e 100644 --- a/view/LocaleFileMap.js +++ b/view/LocaleFileMap.js @@ -33,9 +33,11 @@ module.exports = class LocaleFileMap extends Base { createLocaleMap () { this._locales = {}; const localePath = path.join(this.baseDirectory, this.localeDirectory); - for (const language of fs.readdirSync(localePath)) { + const languages = fs.readdirSync(localePath); + for (const language of languages) { const directory = path.join(localePath, language, this.directory); - if (fs.lstatSync(directory).isDirectory()) { + const stat = fs.lstatSync(directory); + if (stat.isDirectory()) { const fileMap = ClassHelper.spawn(FileMap, {directory}); if (!fileMap.isEmpty()) { this._locales[language] = fileMap; @@ -45,11 +47,13 @@ module.exports = class LocaleFileMap extends Base { } get (name, language) { - return this._locales[language]?.get(name) || this._default.get(name); + return this._locales[language]?.get(name) + || this._default.get(name); } isEmpty () { - return this._default.isEmpty() && Object.values(this._locales).length === 0; + return this._default.isEmpty() + && Object.values(this._locales).length === 0; } }; diff --git a/view/Theme.js b/view/Theme.js index 70b8d2c..7bc869c 100644 --- a/view/Theme.js +++ b/view/Theme.js @@ -55,7 +55,8 @@ module.exports = class Theme extends Base { // TEMPLATE getTemplate () { - return this._templates.get(...arguments) || this.parent?.getTemplate(...arguments); + return this._templates.get(...arguments) + || this.parent?.getTemplate(...arguments); } getInternalTemplate () { @@ -68,7 +69,8 @@ module.exports = class Theme extends Base { getTemplateFromOriginal () { return this._templates.get(...arguments) - || this.originalParentView && this.parent?.getTemplateFromOriginal(...arguments); + || this.originalParentView + && this.parent?.getTemplateFromOriginal(...arguments); } /** @@ -76,7 +78,8 @@ module.exports = class Theme extends Base { */ getTemplateFromSameView () { return this._templates.get(...arguments) - || this.sameParentView && this.parent?.getTemplateFromSameView(...arguments); + || this.sameParentView + && this.parent?.getTemplateFromSameView(...arguments); } /** @@ -85,7 +88,7 @@ module.exports = class Theme extends Base { getTemplateFromOriginalOrSameView () { return this._templates.get(...arguments) || (this.originalParentView || this.sameParentView) - && this.parent?.getTemplateFromOriginalOrSameView(...arguments); + && this.parent?.getTemplateFromOriginalOrSameView(...arguments); } getClosestAncestorTemplate () { @@ -106,7 +109,8 @@ module.exports = class Theme extends Base { // MODEL getModel () { - return this.getInternalModel(...arguments) || this.parent?.getModel(...arguments); + return this.getInternalModel(...arguments) + || this.parent?.getModel(...arguments); } getInternalModel () { @@ -119,18 +123,20 @@ module.exports = class Theme extends Base { getModelFromOriginal () { return this._models.get(...arguments) - || this.originalParentView && this.parent?.getModelFromOriginal(...arguments); + || this.originalParentView + && this.parent?.getModelFromOriginal(...arguments); } getModelFromSameView () { return this._models.get(...arguments) - || this.sameParentView && this.parent?.getModelFromSameView(...arguments); + || this.sameParentView + && this.parent?.getModelFromSameView(...arguments); } getModelFromOriginalOrSameView () { return this._models.get(...arguments) || (this.originalParentView || this.sameParentView) - && this.parent?.getModelFromOriginalOrSameView(...arguments); + && this.parent?.getModelFromOriginalOrSameView(...arguments); } }; diff --git a/view/ThemeSet.js b/view/ThemeSet.js index f8f9e4c..300fc5c 100644 --- a/view/ThemeSet.js +++ b/view/ThemeSet.js @@ -63,7 +63,8 @@ module.exports = class ThemeSet extends Base { const names = fs.readdirSync(this.themeDirectory); for (const name of names) { const dir = path.join(this.themeDirectory, name); - if (fs.lstatSync(dir).isDirectory()) { + const stat = fs.lstatSync(dir); + if (stat.isDirectory()) { this.createTheme(name, dir); } } @@ -79,8 +80,8 @@ module.exports = class ThemeSet extends Base { } setParents () { - for (const name of Object.keys(this._themes)) { - this._themes[name].parent = this.getParentByName(name) || this._defaultTheme; + for (const [name, theme] of Object.entries(this._themes)) { + theme.parent = this.getParentByName(name) || this._defaultTheme; } } diff --git a/view/Widget.js b/view/Widget.js index b3112b1..c4392dd 100644 --- a/view/Widget.js +++ b/view/Widget.js @@ -16,6 +16,8 @@ module.exports = class Widget extends Base { constructor (config) { super({ cacheComponentId: 'cache', + caching: false, + cacheDuration: 60, ...config }); this.module = this.view.module; diff --git a/web/Response.js b/web/Response.js index 018d8f3..349ab6c 100644 --- a/web/Response.js +++ b/web/Response.js @@ -104,7 +104,8 @@ module.exports = class Response extends Base { const res = this.controller.res; if (res.headersSent) { const {method, originalUrl} = this.controller.req; - return this.controller.log('error', `Headers already sent: ${method}: ${originalUrl}`); + const message = `Headers already sent: ${method}: ${originalUrl}`; + return this.controller.log('error', message); } if (this.code) { res.status(this.code); diff --git a/web/Router.js b/web/Router.js index 9fde7af..3180bd6 100644 --- a/web/Router.js +++ b/web/Router.js @@ -30,9 +30,12 @@ module.exports = class Router extends Base { } afterModuleInit () { - this.defaultModule - ? this.addDefaultModule(this.defaultModule) - : this.addDefaultAction(this.getDefaultController()); + if (this.defaultModule) { + this.addDefaultModule(this.defaultModule) + } else { + const controller = this.getDefaultController(); + this.addDefaultAction(controller); + } if (this.errors) { this.addErrorHandlers(this.errors); } @@ -54,13 +57,14 @@ module.exports = class Router extends Base { } getInheritedControllerMap (module) { - if (!module.original) { - return this.getControllerMap(module.getControllerDirectory()); + const dir = module.getControllerDirectory(); + const data = this.getControllerMap(dir); + const original = module.original; + if (!original) { + return data; } - return { - ...this.getInheritedControllerMap(module.original), - ...this.getControllerMap(module.getControllerDirectory()) - }; + const inheritedData = this.getInheritedControllerMap(original); + return {...inheritedData, ...data}; } getDefaultController () { @@ -74,14 +78,15 @@ module.exports = class Router extends Base { } getControllerMap (dir, relative = '') { - let files = []; + let names = []; try { - files = fs.readdirSync(dir); + names = fs.readdirSync(dir); } catch { } const result = {}; - for (const file of files) { - this.setControllerMapFile(path.join(dir, file), relative, result); + for (const name of names) { + const file = path.join(dir, name); + this.setControllerMapFile(file, relative, result); } return result; } @@ -90,10 +95,12 @@ module.exports = class Router extends Base { const stat = fs.lstatSync(file); if (stat.isDirectory()) { const prefix = `${relative}${path.basename(file)}-`; - Object.assign(map, this.getControllerMap(file, prefix)); + const data = this.getControllerMap(file, prefix); + Object.assign(map, data); } else { const controller = require(file); - map[relative + controller.getRouteName()] = controller; + const key = relative + controller.getRouteName(); + map[key] = controller; } } @@ -107,7 +114,8 @@ module.exports = class Router extends Base { addDefaultAction (Controller) { if (Controller?.DEFAULT_ACTION) { - if (Controller.getActionNames().includes(Controller.DEFAULT_ACTION)) { + const names = Controller.getActionNames(); + if (names.includes(Controller.DEFAULT_ACTION)) { this.addAction(Controller.DEFAULT_ACTION, Controller, ''); } } @@ -117,7 +125,8 @@ module.exports = class Router extends Base { for (const key of Object.keys(this._controllerMap)) { const route = `/${key}`; const Controller = this._controllerMap[key]; - for (const name of Controller.getActionNames()) { + const names = Controller.getActionNames(); + for (const name of names) { const action = this.constructor.createActionRouteName(name); this.addAction(name, Controller, `${route}/${action}`); if (Controller.DEFAULT_ACTION === name) { diff --git a/web/packer/FilePack.js b/web/packer/FilePack.js index 579dfbe..efbc3a9 100644 --- a/web/packer/FilePack.js +++ b/web/packer/FilePack.js @@ -56,7 +56,8 @@ module.exports = class FilePack extends Base { } async packDirectory (dir, baseName) { - for (let name of await FileHelper.readDirectory(dir)) { + const names = await FileHelper.readDirectory(dir); + for (let name of names) { const file = dir + '/' + name; const stat = await FileHelper.getStat(file); name = baseName + '/' + name; diff --git a/web/session/DatabaseSessionStore.js b/web/session/DatabaseSessionStore.js index 29ab8c7..108fd82 100644 --- a/web/session/DatabaseSessionStore.js +++ b/web/session/DatabaseSessionStore.js @@ -56,7 +56,8 @@ module.exports = class DatabaseSessionStore extends Base { deleteExpired () { if (this.session.lifetime) { - const date = new Date(Date.now() - this.session.lifetime); + const time = Date.now() - this.session.lifetime; + const date = new Date(time); return this.find(['<', 'updatedAt', date]).delete(); } } diff --git a/web/session/SessionStore.js b/web/session/SessionStore.js index ec9a8a0..b49a747 100644 --- a/web/session/SessionStore.js +++ b/web/session/SessionStore.js @@ -17,7 +17,7 @@ module.exports = class SessionStore extends Base { /** * Get session data by ID - * @param {string} id - Session ID + * @param {string} id - Session ID * @param {function} callback - Transmit error or session data: callback(err, data) */ get (id, callback) { @@ -26,8 +26,8 @@ module.exports = class SessionStore extends Base { /** * Set session data by ID - * @param {string} id - Session ID - * @param {Object} data - Session data + * @param {string} id - Session ID + * @param {Object} data - Session data * @param {function} callback - After done */ set (id, data, callback) { @@ -36,8 +36,8 @@ module.exports = class SessionStore extends Base { /** * Update session access time - * @param {string} id - Session ID - * @param {Object} data - Session data + * @param {string} id - Session ID + * @param {Object} data - Session data * @param {function} callback - After done */ touch (id, data, callback) { @@ -46,7 +46,7 @@ module.exports = class SessionStore extends Base { /** * Delete session by ID - * @param {string} id - Session ID + * @param {string} id - Session ID * @param {function} callback - After done */ destroy (id, callback) {