mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
test: Make oclif commands testable (#3571)
* ➕ Add `@oclif/core` * 📦 Update `package-lock.json` * 📘 Export `Logger` for use as type * ✨ Create `BaseCommand` * 🐛 Prevent DB re-init * ♻️ Refactor `reset` command * 🧪 Fix `reset` test * 👕 Add lint exception Co-authored-by: Jan Oberhauser <janober@users.noreply.github.com>
This commit is contained in:
275
package-lock.json
generated
275
package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"@kafkajs/confluent-schema-registry": "1.0.6",
|
"@kafkajs/confluent-schema-registry": "1.0.6",
|
||||||
"@n8n_io/riot-tmpl": "^1.0.1",
|
"@n8n_io/riot-tmpl": "^1.0.1",
|
||||||
"@oclif/command": "^1.5.18",
|
"@oclif/command": "^1.5.18",
|
||||||
|
"@oclif/core": "^1.9.3",
|
||||||
"@oclif/dev-cli": "^1.22.2",
|
"@oclif/dev-cli": "^1.22.2",
|
||||||
"@oclif/errors": "^1.2.2",
|
"@oclif/errors": "^1.2.2",
|
||||||
"@rudderstack/rudder-sdk-node": "1.0.6",
|
"@rudderstack/rudder-sdk-node": "1.0.6",
|
||||||
@@ -11404,6 +11405,160 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@oclif/core": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oclif/core/-/core-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-npxWULRu+iW9AuUNoCH118MNI8cxYIkcWkknz3mCDumTo11FC+h3OY1cMtlclqZHfZcDHh4iaSkNMX/7se9GUQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@oclif/linewrap": "^1.0.0",
|
||||||
|
"@oclif/screen": "^3.0.2",
|
||||||
|
"ansi-escapes": "^4.3.2",
|
||||||
|
"ansi-styles": "^4.3.0",
|
||||||
|
"cardinal": "^2.1.1",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"clean-stack": "^3.0.1",
|
||||||
|
"cli-progress": "^3.10.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"ejs": "^3.1.6",
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"get-package-type": "^0.1.0",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"hyperlinker": "^1.0.0",
|
||||||
|
"indent-string": "^4.0.0",
|
||||||
|
"is-wsl": "^2.2.0",
|
||||||
|
"js-yaml": "^3.14.1",
|
||||||
|
"natural-orderby": "^2.0.3",
|
||||||
|
"object-treeify": "^1.1.33",
|
||||||
|
"password-prompt": "^1.1.2",
|
||||||
|
"semver": "^7.3.7",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"strip-ansi": "^6.0.1",
|
||||||
|
"supports-color": "^8.1.1",
|
||||||
|
"supports-hyperlinks": "^2.2.0",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"widest-line": "^3.1.0",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/@oclif/screen": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-S/SF/XYJeevwIgHFmVDAFRUvM3m+OjhvCAYMk78ZJQCYCQ5wS7j+LTt1ZEv2jpEEGg2tx/F6TYYWxddNAYHrFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/chalk/node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/fs-extra": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"at-least-node": "^1.0.0",
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/jsonfile": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/semver": {
|
||||||
|
"version": "7.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/supports-color": {
|
||||||
|
"version": "8.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||||
|
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/tslib": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/universalify": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@oclif/core/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
|
},
|
||||||
"node_modules/@oclif/dev-cli": {
|
"node_modules/@oclif/dev-cli": {
|
||||||
"version": "1.26.10",
|
"version": "1.26.10",
|
||||||
"resolved": "https://registry.npmjs.org/@oclif/dev-cli/-/dev-cli-1.26.10.tgz",
|
"resolved": "https://registry.npmjs.org/@oclif/dev-cli/-/dev-cli-1.26.10.tgz",
|
||||||
@@ -69729,6 +69884,126 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@oclif/core": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oclif/core/-/core-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-npxWULRu+iW9AuUNoCH118MNI8cxYIkcWkknz3mCDumTo11FC+h3OY1cMtlclqZHfZcDHh4iaSkNMX/7se9GUQ==",
|
||||||
|
"requires": {
|
||||||
|
"@oclif/linewrap": "^1.0.0",
|
||||||
|
"@oclif/screen": "^3.0.2",
|
||||||
|
"ansi-escapes": "^4.3.2",
|
||||||
|
"ansi-styles": "^4.3.0",
|
||||||
|
"cardinal": "^2.1.1",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"clean-stack": "^3.0.1",
|
||||||
|
"cli-progress": "^3.10.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"ejs": "^3.1.6",
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"get-package-type": "^0.1.0",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"hyperlinker": "^1.0.0",
|
||||||
|
"indent-string": "^4.0.0",
|
||||||
|
"is-wsl": "^2.2.0",
|
||||||
|
"js-yaml": "^3.14.1",
|
||||||
|
"natural-orderby": "^2.0.3",
|
||||||
|
"object-treeify": "^1.1.33",
|
||||||
|
"password-prompt": "^1.1.2",
|
||||||
|
"semver": "^7.3.7",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"strip-ansi": "^6.0.1",
|
||||||
|
"supports-color": "^8.1.1",
|
||||||
|
"supports-hyperlinks": "^2.2.0",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"widest-line": "^3.1.0",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@oclif/screen": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-S/SF/XYJeevwIgHFmVDAFRUvM3m+OjhvCAYMk78ZJQCYCQ5wS7j+LTt1ZEv2jpEEGg2tx/F6TYYWxddNAYHrFQ=="
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||||
|
"requires": {
|
||||||
|
"at-least-node": "^1.0.0",
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.6",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "7.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "8.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||||
|
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||||
|
},
|
||||||
|
"universalify": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@oclif/dev-cli": {
|
"@oclif/dev-cli": {
|
||||||
"version": "1.26.10",
|
"version": "1.26.10",
|
||||||
"resolved": "https://registry.npmjs.org/@oclif/dev-cli/-/dev-cli-1.26.10.tgz",
|
"resolved": "https://registry.npmjs.org/@oclif/dev-cli/-/dev-cli-1.26.10.tgz",
|
||||||
|
|||||||
57
packages/cli/commands/BaseCommand.ts
Normal file
57
packages/cli/commands/BaseCommand.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Command } from '@oclif/core';
|
||||||
|
import { LoggerProxy } from 'n8n-workflow';
|
||||||
|
import { getLogger, Logger } from '../src/Logger';
|
||||||
|
import { User } from '../src/databases/entities/User';
|
||||||
|
import { Db } from '../src';
|
||||||
|
|
||||||
|
export abstract class BaseCommand extends Command {
|
||||||
|
logger: Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
async init(): Promise<void> {
|
||||||
|
this.logger = getLogger();
|
||||||
|
LoggerProxy.init(this.logger);
|
||||||
|
|
||||||
|
await Db.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async finally(): Promise<void> {
|
||||||
|
if (process.env.NODE_ENV === 'test') return;
|
||||||
|
|
||||||
|
this.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Management utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
defaultUserProps = {
|
||||||
|
firstName: null,
|
||||||
|
lastName: null,
|
||||||
|
email: null,
|
||||||
|
password: null,
|
||||||
|
resetPasswordToken: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
async getInstanceOwner(): Promise<User> {
|
||||||
|
const globalRole = await Db.collections.Role.findOneOrFail({
|
||||||
|
name: 'owner',
|
||||||
|
scope: 'global',
|
||||||
|
});
|
||||||
|
|
||||||
|
const owner = await Db.collections.User.findOne({ globalRole });
|
||||||
|
|
||||||
|
if (owner) return owner;
|
||||||
|
|
||||||
|
const user = new User();
|
||||||
|
|
||||||
|
Object.assign(user, { ...this.defaultUserProps, globalRole });
|
||||||
|
|
||||||
|
await Db.collections.User.save(user);
|
||||||
|
|
||||||
|
return Db.collections.User.findOneOrFail({ globalRole });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,85 +1,51 @@
|
|||||||
/* eslint-disable no-console */
|
|
||||||
|
|
||||||
import Command from '@oclif/command';
|
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
import { LoggerProxy } from 'n8n-workflow';
|
|
||||||
import { Db } from '../../src';
|
import { Db } from '../../src';
|
||||||
import { User } from '../../src/databases/entities/User';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
import { getLogger } from '../../src/Logger';
|
|
||||||
|
|
||||||
export class Reset extends Command {
|
export class Reset extends BaseCommand {
|
||||||
static description = '\nResets the database to the default user state';
|
static description = '\nResets the database to the default user state';
|
||||||
|
|
||||||
private defaultUserProps = {
|
|
||||||
firstName: null,
|
|
||||||
lastName: null,
|
|
||||||
email: null,
|
|
||||||
password: null,
|
|
||||||
resetPasswordToken: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
async run(): Promise<void> {
|
async run(): Promise<void> {
|
||||||
const logger = getLogger();
|
const owner = await this.getInstanceOwner();
|
||||||
LoggerProxy.init(logger);
|
|
||||||
await Db.init();
|
|
||||||
|
|
||||||
try {
|
const ownerWorkflowRole = await Db.collections.Role.findOneOrFail({
|
||||||
const owner = await this.getInstanceOwner();
|
|
||||||
|
|
||||||
const ownerWorkflowRole = await Db.collections.Role.findOneOrFail({
|
|
||||||
name: 'owner',
|
|
||||||
scope: 'workflow',
|
|
||||||
});
|
|
||||||
|
|
||||||
const ownerCredentialRole = await Db.collections.Role.findOneOrFail({
|
|
||||||
name: 'owner',
|
|
||||||
scope: 'credential',
|
|
||||||
});
|
|
||||||
|
|
||||||
await Db.collections.SharedWorkflow.update(
|
|
||||||
{ user: { id: Not(owner.id) }, role: ownerWorkflowRole },
|
|
||||||
{ user: owner },
|
|
||||||
);
|
|
||||||
|
|
||||||
await Db.collections.SharedCredentials.update(
|
|
||||||
{ user: { id: Not(owner.id) }, role: ownerCredentialRole },
|
|
||||||
{ user: owner },
|
|
||||||
);
|
|
||||||
await Db.collections.User.delete({ id: Not(owner.id) });
|
|
||||||
await Db.collections.User.save(Object.assign(owner, this.defaultUserProps));
|
|
||||||
|
|
||||||
await Db.collections.Settings.update(
|
|
||||||
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
|
||||||
{ value: 'false' },
|
|
||||||
);
|
|
||||||
await Db.collections.Settings.update(
|
|
||||||
{ key: 'userManagement.skipInstanceOwnerSetup' },
|
|
||||||
{ value: 'false' },
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error resetting database. See log messages for details.');
|
|
||||||
if (error instanceof Error) logger.error(error.message);
|
|
||||||
this.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.info('Successfully reset the database to default user state.');
|
|
||||||
this.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getInstanceOwner(): Promise<User> {
|
|
||||||
const globalRole = await Db.collections.Role.findOneOrFail({
|
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'global',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOne({ globalRole });
|
const ownerCredentialRole = await Db.collections.Role.findOneOrFail({
|
||||||
|
name: 'owner',
|
||||||
|
scope: 'credential',
|
||||||
|
});
|
||||||
|
|
||||||
if (owner) return owner;
|
await Db.collections.SharedWorkflow.update(
|
||||||
|
{ user: { id: Not(owner.id) }, role: ownerWorkflowRole },
|
||||||
|
{ user: owner },
|
||||||
|
);
|
||||||
|
|
||||||
const user = new User();
|
await Db.collections.SharedCredentials.update(
|
||||||
|
{ user: { id: Not(owner.id) }, role: ownerCredentialRole },
|
||||||
|
{ user: owner },
|
||||||
|
);
|
||||||
|
|
||||||
await Db.collections.User.save(Object.assign(user, { ...this.defaultUserProps, globalRole }));
|
await Db.collections.User.delete({ id: Not(owner.id) });
|
||||||
|
await Db.collections.User.save(Object.assign(owner, this.defaultUserProps));
|
||||||
|
|
||||||
return Db.collections.User.findOneOrFail({ globalRole });
|
await Db.collections.Settings.update(
|
||||||
|
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||||
|
{ value: 'false' },
|
||||||
|
);
|
||||||
|
await Db.collections.Settings.update(
|
||||||
|
{ key: 'userManagement.skipInstanceOwnerSetup' },
|
||||||
|
{ value: 'false' },
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.info('Successfully reset the database to default user state.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async catch(error: Error): Promise<void> {
|
||||||
|
this.logger.error('Error resetting database. See log messages for details.');
|
||||||
|
this.logger.error(error.message);
|
||||||
|
this.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
"typescript": "~4.6.0"
|
"typescript": "~4.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@oclif/core": "^1.9.3",
|
||||||
"@apidevtools/swagger-cli": "4.0.0",
|
"@apidevtools/swagger-cli": "4.0.0",
|
||||||
"@oclif/command": "^1.5.18",
|
"@oclif/command": "^1.5.18",
|
||||||
"@oclif/errors": "^1.2.2",
|
"@oclif/errors": "^1.2.2",
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ export function linkRepository<Entity>(entityClass: EntityTarget<Entity>): Repos
|
|||||||
export async function init(
|
export async function init(
|
||||||
testConnectionOptions?: ConnectionOptions,
|
testConnectionOptions?: ConnectionOptions,
|
||||||
): Promise<IDatabaseCollections> {
|
): Promise<IDatabaseCollections> {
|
||||||
|
if (isInitialized) return collections;
|
||||||
|
|
||||||
const dbType = (await GenericHelpers.getConfigValue('database.type')) as DatabaseType;
|
const dbType = (await GenericHelpers.getConfigValue('database.type')) as DatabaseType;
|
||||||
const n8nFolder = UserSettings.getUserN8nFolderPath();
|
const n8nFolder = UserSettings.getUserN8nFolderPath();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-shadow */
|
/* eslint-disable @typescript-eslint/no-shadow */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
|
|
||||||
import { inspect } from 'util';
|
import { inspect } from 'util';
|
||||||
import winston from 'winston';
|
import winston from 'winston';
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ import callsites from 'callsites';
|
|||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
class Logger implements ILogger {
|
export class Logger implements ILogger {
|
||||||
private logger: winston.Logger;
|
private logger: winston.Logger;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -71,7 +72,7 @@ class Logger implements ILogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log(type: LogTypes, message: string, meta: object = {}) {
|
log(type: LogTypes, message: string, meta: object = {}): void {
|
||||||
const callsite = callsites();
|
const callsite = callsites();
|
||||||
// We are using the third array element as the structure is as follows:
|
// We are using the third array element as the structure is as follows:
|
||||||
// [0]: this file
|
// [0]: this file
|
||||||
@@ -93,23 +94,23 @@ class Logger implements ILogger {
|
|||||||
|
|
||||||
// Convenience methods below
|
// Convenience methods below
|
||||||
|
|
||||||
debug(message: string, meta: object = {}) {
|
debug(message: string, meta: object = {}): void {
|
||||||
this.log('debug', message, meta);
|
this.log('debug', message, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
info(message: string, meta: object = {}) {
|
info(message: string, meta: object = {}): void {
|
||||||
this.log('info', message, meta);
|
this.log('info', message, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(message: string, meta: object = {}) {
|
error(message: string, meta: object = {}): void {
|
||||||
this.log('error', message, meta);
|
this.log('error', message, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose(message: string, meta: object = {}) {
|
verbose(message: string, meta: object = {}): void {
|
||||||
this.log('verbose', message, meta);
|
this.log('verbose', message, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(message: string, meta: object = {}) {
|
warn(message: string, meta: object = {}): void {
|
||||||
this.log('warn', message, meta);
|
this.log('warn', message, meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { execSync } from 'child_process';
|
|
||||||
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { Db } from '../../../src';
|
import { Db } from '../../../src';
|
||||||
|
import { Reset } from '../../../commands/user-management/reset';
|
||||||
import * as utils from '../shared/utils';
|
import * as utils from '../shared/utils';
|
||||||
import type { Role } from '../../../src/databases/entities/Role';
|
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import { randomEmail, randomName, randomValidPassword } from '../shared/random';
|
import type { Role } from '../../../src/databases/entities/Role';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
let testDbName = '';
|
||||||
@@ -21,6 +18,10 @@ beforeAll(async () => {
|
|||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await testDb.truncate(['User'], testDbName);
|
||||||
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate(testDbName);
|
||||||
});
|
});
|
||||||
@@ -28,17 +29,19 @@ afterAll(async () => {
|
|||||||
test('user-management:reset should reset DB to default user state', async () => {
|
test('user-management:reset should reset DB to default user state', async () => {
|
||||||
await testDb.createUser({ globalRole: globalOwnerRole });
|
await testDb.createUser({ globalRole: globalOwnerRole });
|
||||||
|
|
||||||
const command = [path.join('bin', 'n8n'), 'user-management:reset'].join(' ');
|
await Reset.run();
|
||||||
|
|
||||||
execSync(command);
|
const user = await Db.collections.User.findOne({ globalRole: globalOwnerRole });
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne();
|
if (!user) {
|
||||||
|
fail('No owner found after DB reset to default user state');
|
||||||
|
}
|
||||||
|
|
||||||
expect(user?.email).toBeNull();
|
expect(user.email).toBeNull();
|
||||||
expect(user?.firstName).toBeNull();
|
expect(user.firstName).toBeNull();
|
||||||
expect(user?.lastName).toBeNull();
|
expect(user.lastName).toBeNull();
|
||||||
expect(user?.password).toBeNull();
|
expect(user.password).toBeNull();
|
||||||
expect(user?.resetPasswordToken).toBeNull();
|
expect(user.resetPasswordToken).toBeNull();
|
||||||
expect(user?.resetPasswordTokenExpiration).toBeNull();
|
expect(user.resetPasswordTokenExpiration).toBeNull();
|
||||||
expect(user?.personalizationAnswers).toBeNull();
|
expect(user.personalizationAnswers).toBeNull();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user