@saltcorn/cli 0.7.1-beta.3 → 0.7.2-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +244 -49
- package/npm-shrinkwrap.json +1093 -686
- package/oclif.manifest.json +1 -1
- package/package.json +11 -8
- package/src/commands/add-schema.js +23 -1
- package/src/commands/backup.js +7 -3
- package/src/commands/configuration-check.js +3 -10
- package/src/commands/create-user.js +14 -8
- package/src/commands/delete-tenants.js +24 -20
- package/src/commands/delete-user.js +105 -0
- package/src/commands/get-cfg.js +63 -0
- package/src/commands/modify-user.js +163 -0
- package/src/commands/release.js +20 -9
- package/src/commands/reset-schema.js +11 -2
- package/src/commands/restore.js +5 -0
- package/src/commands/rm-tenant.js +39 -6
- package/src/commands/run-tests.js +44 -16
- package/src/commands/setup.js +48 -23
- package/src/common.js +28 -6
- package/src/index.js +9 -2
- package/CHANGELOG.md +0 -8
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-cli
|
|
3
|
+
* @module commands/modify-user
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// todo support for users without emails (using user.id)
|
|
7
|
+
const { Command, flags } = require("@oclif/command");
|
|
8
|
+
const { cli } = require("cli-ux");
|
|
9
|
+
const { maybe_as_tenant, init_some_tenants } = require("../common");
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* ModifyUserCommand Class
|
|
14
|
+
* @extends oclif.Command
|
|
15
|
+
* @category saltcorn-cli
|
|
16
|
+
*/
|
|
17
|
+
class ModifyUserCommand extends Command {
|
|
18
|
+
/**
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async run() {
|
|
22
|
+
|
|
23
|
+
const User = require("@saltcorn/data/models/user");
|
|
24
|
+
|
|
25
|
+
const { args } = this.parse(ModifyUserCommand);
|
|
26
|
+
const { flags } = this.parse(ModifyUserCommand);
|
|
27
|
+
|
|
28
|
+
if (flags.admin && flags.role && flags.role !== "admin") {
|
|
29
|
+
console.error("Error: specify at most one of admin and role");
|
|
30
|
+
this.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// init tenant
|
|
34
|
+
await init_some_tenants(flags.tenant);
|
|
35
|
+
|
|
36
|
+
// run function as specified tenant
|
|
37
|
+
await maybe_as_tenant(flags.tenant, async () => {
|
|
38
|
+
// role_id
|
|
39
|
+
let role_id; // = flags.admin ? 1 : 8;
|
|
40
|
+
if (flags.admin) role_id = 1;
|
|
41
|
+
else if (flags.role) {
|
|
42
|
+
const roles = await User.get_roles();
|
|
43
|
+
const role = roles.find((r) => r.role === flags.role);
|
|
44
|
+
if (!role) {
|
|
45
|
+
console.error(`Error: role ${flags.role} not found`);
|
|
46
|
+
this.exit(1);
|
|
47
|
+
}
|
|
48
|
+
role_id = role.id;
|
|
49
|
+
}
|
|
50
|
+
// email
|
|
51
|
+
let email;
|
|
52
|
+
if (flags.email) email = flags.email;
|
|
53
|
+
else if (flags.imode) email = await cli.prompt("New Email address", { default : args.user_email });
|
|
54
|
+
if(email === args.user_email) email = undefined; // little trick - we won't update email if it already same
|
|
55
|
+
if (email)
|
|
56
|
+
if (!User.valid_email(email)){
|
|
57
|
+
console.error(`Error: Email is invalid`);
|
|
58
|
+
this.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// password
|
|
62
|
+
// todo check for repeated passwords
|
|
63
|
+
let password;
|
|
64
|
+
if (flags.password) password = flags.password;
|
|
65
|
+
else if (flags.imode) password = await cli.prompt("New Password", { type: "hide" });
|
|
66
|
+
if (password)
|
|
67
|
+
if (User.unacceptable_password_reason(password)){
|
|
68
|
+
console.error(`Error: ${User.unacceptable_password_reason(password)}`);
|
|
69
|
+
this.exit(1);
|
|
70
|
+
}
|
|
71
|
+
// check that user with new email does not exists
|
|
72
|
+
const u_new_email = await User.findOne({ email });
|
|
73
|
+
if(u_new_email !== null&&args.user_email!==email){
|
|
74
|
+
console.error(`Error: Cannot change email from ${args.user_email} to ${email}. User with email ${email} exists`);
|
|
75
|
+
this.exit(1);
|
|
76
|
+
}
|
|
77
|
+
// try to find user
|
|
78
|
+
const u = await User.findOne({ email: args.user_email });
|
|
79
|
+
if(u === null){
|
|
80
|
+
console.error(`Error: User ${args.user_email} is not found`);
|
|
81
|
+
this.exit(1);
|
|
82
|
+
}
|
|
83
|
+
if(!u instanceof User){
|
|
84
|
+
console.error(`Error: ${u.error}`);
|
|
85
|
+
this.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// make changes
|
|
89
|
+
if (email && role_id)
|
|
90
|
+
await u.update({ email, role_id });
|
|
91
|
+
else if(email)
|
|
92
|
+
await u.update({ email });
|
|
93
|
+
else if(role_id)
|
|
94
|
+
await u.update({ role_id });
|
|
95
|
+
|
|
96
|
+
if (password)
|
|
97
|
+
await u.changePasswordTo(password, false);
|
|
98
|
+
|
|
99
|
+
console.log(`Success: User ${email?email:args.user_email} updated successfully ${
|
|
100
|
+
typeof flags.tenant !== "undefined" ? "in tenant " + flags.tenant : ""
|
|
101
|
+
}`);
|
|
102
|
+
|
|
103
|
+
});
|
|
104
|
+
this.exit(0);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @type {object}
|
|
110
|
+
*/
|
|
111
|
+
ModifyUserCommand.args = [
|
|
112
|
+
{ name: "user_email", required: true, description: "User to modify" },
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @type {string}
|
|
117
|
+
*/
|
|
118
|
+
ModifyUserCommand.description = `Modify (update) user.
|
|
119
|
+
|
|
120
|
+
Command changes the user specified by USER_EMAIL.
|
|
121
|
+
|
|
122
|
+
You can change the user group, password and email.
|
|
123
|
+
|
|
124
|
+
NOTE that -a and -r role (--role=role) can give conflict.
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @type {string}
|
|
129
|
+
*/
|
|
130
|
+
ModifyUserCommand.help = `Modify (update) user.
|
|
131
|
+
|
|
132
|
+
Command changes the user specified by USER_EMAIL.
|
|
133
|
+
|
|
134
|
+
You can change the user group, password and email.
|
|
135
|
+
|
|
136
|
+
NOTE that -a and -r role (--role=role) can give conflict.
|
|
137
|
+
`;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @type {object}
|
|
141
|
+
*/
|
|
142
|
+
ModifyUserCommand.flags = {
|
|
143
|
+
admin: flags.boolean({ char: "a", description: "make user be Admin" }),
|
|
144
|
+
tenant: flags.string({
|
|
145
|
+
char: "t",
|
|
146
|
+
description: "tenant",
|
|
147
|
+
}),
|
|
148
|
+
email: flags.string({
|
|
149
|
+
char: "e",
|
|
150
|
+
description: "new email",
|
|
151
|
+
}),
|
|
152
|
+
role: flags.string({
|
|
153
|
+
char: "r",
|
|
154
|
+
description: "new role (can conflict with -a option)",
|
|
155
|
+
}),
|
|
156
|
+
password: flags.string({
|
|
157
|
+
char: "p",
|
|
158
|
+
description: "new password",
|
|
159
|
+
}),
|
|
160
|
+
imode: flags.boolean({ char: "i", description: "interactive mode" }),
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
module.exports = ModifyUserCommand;
|
package/src/commands/release.js
CHANGED
|
@@ -24,6 +24,7 @@ class ReleaseCommand extends Command {
|
|
|
24
24
|
"@saltcorn/e2e": { dir: "e2e" },
|
|
25
25
|
"@saltcorn/db-common": { dir: "db-common", publish: true },
|
|
26
26
|
"@saltcorn/sqlite": { dir: "sqlite", publish: true },
|
|
27
|
+
"@saltcorn/sqlite-mobile": { dir: "sqlite-mobile", publish: true },
|
|
27
28
|
"@saltcorn/postgres": { dir: "postgres", publish: true },
|
|
28
29
|
"@saltcorn/types": { dir: "saltcorn-types", publish: true },
|
|
29
30
|
"@saltcorn/builder": { dir: "saltcorn-builder", publish: true },
|
|
@@ -37,28 +38,38 @@ class ReleaseCommand extends Command {
|
|
|
37
38
|
"@saltcorn/base-plugin": { dir: "saltcorn-base-plugin", publish: true },
|
|
38
39
|
//"saltcorn-cli", publish: true},
|
|
39
40
|
"@saltcorn/markup": { dir: "saltcorn-markup", publish: true },
|
|
41
|
+
"@saltcorn/mobile-app": { dir: "saltcorn-mobile-app", publish: true },
|
|
42
|
+
"@saltcorn/mobile-builder": {
|
|
43
|
+
dir: "saltcorn-mobile-builder",
|
|
44
|
+
publish: true,
|
|
45
|
+
},
|
|
40
46
|
"@saltcorn/sbadmin2": { dir: "saltcorn-sbadmin2", publish: true },
|
|
41
47
|
};
|
|
42
48
|
|
|
49
|
+
const updateDependencies = (json, dpkgnm, version) => {
|
|
50
|
+
if (json.dependencies && json.dependencies[dpkgnm])
|
|
51
|
+
json.dependencies[dpkgnm] = version;
|
|
52
|
+
if (json.devDependencies && json.devDependencies[dpkgnm])
|
|
53
|
+
json.devDependencies[dpkgnm] = version;
|
|
54
|
+
if (json.optionalDependencies && json.optionalDependencies[dpkgnm])
|
|
55
|
+
json.optionalDependencies[dpkgnm] = version;
|
|
56
|
+
};
|
|
57
|
+
|
|
43
58
|
const updatePkgJson = (dir) => {
|
|
44
59
|
const json = require(`../../../${dir}/package.json`);
|
|
45
60
|
json.version = version;
|
|
46
61
|
if (json.dependencies || json.devDependencies)
|
|
47
62
|
Object.keys(pkgs).forEach((dpkgnm) => {
|
|
48
|
-
|
|
49
|
-
json.dependencies[dpkgnm] = version;
|
|
50
|
-
if (json.devDependencies && json.devDependencies[dpkgnm])
|
|
51
|
-
json.devDependencies[dpkgnm] = version;
|
|
52
|
-
if (json.optionalDependencies && json.optionalDependencies[dpkgnm])
|
|
53
|
-
json.optionalDependencies[dpkgnm] = version;
|
|
63
|
+
updateDependencies(json, dpkgnm, version);
|
|
54
64
|
});
|
|
65
|
+
updateDependencies(json, "@saltcorn/cli", version);
|
|
55
66
|
fs.writeFileSync(
|
|
56
67
|
`packages/${dir}/package.json`,
|
|
57
68
|
JSON.stringify(json, null, 2)
|
|
58
69
|
);
|
|
59
70
|
};
|
|
60
71
|
const compileTsFiles = () => {
|
|
61
|
-
spawnSync("npm", ["install"], {
|
|
72
|
+
spawnSync("npm", ["install", "--legacy-peer-deps"], {
|
|
62
73
|
stdio: "inherit",
|
|
63
74
|
cwd: ".",
|
|
64
75
|
});
|
|
@@ -78,7 +89,7 @@ class ReleaseCommand extends Command {
|
|
|
78
89
|
// 1. update version
|
|
79
90
|
// 2. update dependencies for other packages
|
|
80
91
|
// 3. publish
|
|
81
|
-
spawnSync("npm", ["install"], {
|
|
92
|
+
spawnSync("npm", ["install", "--legacy-peer-deps"], {
|
|
82
93
|
stdio: "inherit",
|
|
83
94
|
cwd: `packages/saltcorn-cli/`,
|
|
84
95
|
});
|
|
@@ -93,7 +104,7 @@ class ReleaseCommand extends Command {
|
|
|
93
104
|
// 3. run npm update
|
|
94
105
|
// 3. publish
|
|
95
106
|
updatePkgJson("saltcorn-cli");
|
|
96
|
-
spawnSync("npm", ["update"], {
|
|
107
|
+
spawnSync("npm", ["update","--legacy-peer-deps"], {
|
|
97
108
|
stdio: "inherit",
|
|
98
109
|
cwd: `packages/saltcorn-cli/`,
|
|
99
110
|
});
|
|
@@ -17,7 +17,7 @@ class ResetCommand extends Command {
|
|
|
17
17
|
*/
|
|
18
18
|
async run() {
|
|
19
19
|
const reset = require("@saltcorn/data/db/reset_schema");
|
|
20
|
-
const db = require("@saltcorn/data/db
|
|
20
|
+
const db = require("@saltcorn/data/db");
|
|
21
21
|
const { flags } = this.parse(ResetCommand);
|
|
22
22
|
await maybe_as_tenant(flags.tenant, async () => {
|
|
23
23
|
const schema = db.getTenantSchema();
|
|
@@ -32,6 +32,7 @@ class ResetCommand extends Command {
|
|
|
32
32
|
if (ans) await reset(false, schema);
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
+
console.log(`Success: Command execution successfully`);
|
|
35
36
|
this.exit(0);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
@@ -44,11 +45,19 @@ ResetCommand.description = `Reset the database
|
|
|
44
45
|
This will delete all existing information
|
|
45
46
|
`;
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @type {string}
|
|
50
|
+
*/
|
|
51
|
+
ResetCommand.help = `Reset the database
|
|
52
|
+
...
|
|
53
|
+
This will delete all existing information
|
|
54
|
+
`;
|
|
55
|
+
|
|
47
56
|
/**
|
|
48
57
|
* @type {object}
|
|
49
58
|
*/
|
|
50
59
|
ResetCommand.flags = {
|
|
51
|
-
force: flags.boolean({ char: "f", description: "force" }),
|
|
60
|
+
force: flags.boolean({ char: "f", description: "force command execution" }),
|
|
52
61
|
tenant: flags.string({
|
|
53
62
|
char: "t",
|
|
54
63
|
description: "tenant",
|
package/src/commands/restore.js
CHANGED
|
@@ -91,6 +91,11 @@ RestoreCommand.args = [
|
|
|
91
91
|
*/
|
|
92
92
|
RestoreCommand.description = `Restore a previously backed up database (zip or sqlc format)`;
|
|
93
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @type {string}
|
|
96
|
+
*/
|
|
97
|
+
RestoreCommand.help = `Restore a previously backed up database (zip or sqlc format)`;
|
|
98
|
+
|
|
94
99
|
/**
|
|
95
100
|
* @type {object}
|
|
96
101
|
*/
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module commands/rm-tenant
|
|
4
4
|
*/
|
|
5
5
|
const { Command, flags } = require("@oclif/command");
|
|
6
|
+
const {cli} = require("cli-ux");
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* RmTenantCommand Class
|
|
@@ -14,9 +15,23 @@ class RmTenantCommand extends Command {
|
|
|
14
15
|
* @returns {Promise<void>}
|
|
15
16
|
*/
|
|
16
17
|
async run() {
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const { flags } = this.parse(RmTenantCommand);
|
|
21
|
+
|
|
18
22
|
const { deleteTenant } = require("@saltcorn/admin-models/models/tenant");
|
|
19
|
-
|
|
23
|
+
|
|
24
|
+
if (!flags.force) {
|
|
25
|
+
const ans = await cli.confirm(
|
|
26
|
+
`This will delete tenant ${flags.tenant}. Attention! All tenant data will be lost!\nContinue (y/n)?`);
|
|
27
|
+
if (!ans) {
|
|
28
|
+
console.log(`Success: Command execution canceled`);
|
|
29
|
+
this.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// make changes
|
|
33
|
+
await deleteTenant(flags.tenant);
|
|
34
|
+
|
|
20
35
|
this.exit(0);
|
|
21
36
|
}
|
|
22
37
|
}
|
|
@@ -24,18 +39,36 @@ class RmTenantCommand extends Command {
|
|
|
24
39
|
/**
|
|
25
40
|
* @type {object}
|
|
26
41
|
*/
|
|
27
|
-
RmTenantCommand.args = [
|
|
42
|
+
RmTenantCommand.args = []; /*[
|
|
28
43
|
{ name: "tenant", required: true, description: "Tenant to remove" },
|
|
29
44
|
];
|
|
30
|
-
|
|
45
|
+
*/
|
|
31
46
|
/**
|
|
32
47
|
* @type {string}
|
|
33
48
|
*/
|
|
34
|
-
RmTenantCommand.description = `Remove a tenant
|
|
49
|
+
RmTenantCommand.description = `Remove a tenant.
|
|
50
|
+
Attention! All tenant data will be lost!
|
|
51
|
+
It recommended to make backup of tenant before perform this command.
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @type {object}
|
|
56
|
+
*/
|
|
57
|
+
RmTenantCommand.help = `Remove a tenant.
|
|
58
|
+
Attention! All tenant data will be lost!
|
|
59
|
+
It recommended to make backup of tenant before perform this command.
|
|
60
|
+
`;
|
|
35
61
|
|
|
36
62
|
/**
|
|
37
63
|
* @type {object}
|
|
38
64
|
*/
|
|
39
|
-
RmTenantCommand.flags = {
|
|
65
|
+
RmTenantCommand.flags = {
|
|
66
|
+
force: flags.boolean({ char: "f", description: "force command execution" }),
|
|
67
|
+
tenant: flags.string({
|
|
68
|
+
char: "t",
|
|
69
|
+
description: "tenant",
|
|
70
|
+
required: true,
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
40
73
|
|
|
41
74
|
module.exports = RmTenantCommand;
|
|
@@ -32,26 +32,34 @@ class RunTestsCommand extends Command {
|
|
|
32
32
|
return res;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* @returns {Promise<void>}
|
|
39
|
-
*/
|
|
40
|
-
async e2etest(env) {
|
|
35
|
+
async prepareTestServer(env, port) {
|
|
36
|
+
let serverEnv = JSON.parse(JSON.stringify(env));
|
|
37
|
+
serverEnv.SQLITE_FILEPATH = "/tmp/sctestdb_server";
|
|
41
38
|
spawnSync("packages/saltcorn-cli/bin/saltcorn", ["fixtures", "-r"], {
|
|
42
39
|
stdio: "inherit",
|
|
43
|
-
env,
|
|
40
|
+
env: serverEnv,
|
|
44
41
|
});
|
|
45
42
|
|
|
46
43
|
const server = spawn(
|
|
47
44
|
"packages/saltcorn-cli/bin/saltcorn",
|
|
48
|
-
["serve", "-p",
|
|
45
|
+
["serve", "-p", port],
|
|
49
46
|
{
|
|
50
47
|
stdio: "inherit",
|
|
51
|
-
env,
|
|
48
|
+
env: serverEnv,
|
|
52
49
|
}
|
|
53
50
|
);
|
|
54
51
|
await sleep(2000);
|
|
52
|
+
return server;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param {*} env
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
async e2etest(env) {
|
|
61
|
+
const port = 2987;
|
|
62
|
+
const server = await this.prepareTestServer(env, port);
|
|
55
63
|
const res = await this.do_test(
|
|
56
64
|
"npm",
|
|
57
65
|
["run", "gotest"],
|
|
@@ -63,6 +71,23 @@ class RunTestsCommand extends Command {
|
|
|
63
71
|
if (res.status !== 0) this.exit(res.status);
|
|
64
72
|
}
|
|
65
73
|
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @param {*} env
|
|
77
|
+
*/
|
|
78
|
+
async remoteQueryTest(env, jestParams) {
|
|
79
|
+
const port = 3000;
|
|
80
|
+
env.jwt_secret = require("@saltcorn/data/db").connectObj.jwt_secret;
|
|
81
|
+
const server = await this.prepareTestServer(env, port);
|
|
82
|
+
const res = await this.do_test(
|
|
83
|
+
"npm",
|
|
84
|
+
["run", "remote-queries-test", ...jestParams],
|
|
85
|
+
env,
|
|
86
|
+
"packages/saltcorn-data"
|
|
87
|
+
);
|
|
88
|
+
server.kill();
|
|
89
|
+
if (res.status !== 0) this.exit(res.status);
|
|
90
|
+
}
|
|
66
91
|
/**
|
|
67
92
|
*
|
|
68
93
|
* @param {object} args
|
|
@@ -91,9 +116,6 @@ class RunTestsCommand extends Command {
|
|
|
91
116
|
this.validateCall(args, flags);
|
|
92
117
|
var env;
|
|
93
118
|
|
|
94
|
-
spawnSync("npm", ["run", "tsc"], {
|
|
95
|
-
stdio: "inherit",
|
|
96
|
-
});
|
|
97
119
|
const db = require("@saltcorn/data/db");
|
|
98
120
|
if (db.isSQLite) {
|
|
99
121
|
const testdbpath = "/tmp/sctestdb";
|
|
@@ -103,6 +125,9 @@ class RunTestsCommand extends Command {
|
|
|
103
125
|
await db.changeConnection({ database: "saltcorn_test" });
|
|
104
126
|
env = { ...process.env, PGDATABASE: "saltcorn_test" };
|
|
105
127
|
}
|
|
128
|
+
spawnSync("npm", ["run", "tsc"], {
|
|
129
|
+
stdio: "inherit",
|
|
130
|
+
});
|
|
106
131
|
const fixtures = require("@saltcorn/data/db/fixtures");
|
|
107
132
|
const reset = require("@saltcorn/data/db/reset_schema");
|
|
108
133
|
await reset();
|
|
@@ -123,17 +148,20 @@ class RunTestsCommand extends Command {
|
|
|
123
148
|
}
|
|
124
149
|
if (args.package === "core") {
|
|
125
150
|
await this.do_test("npm", ["run", "test", ...jestParams], env);
|
|
151
|
+
} else if (args.package === "view-queries") {
|
|
152
|
+
await this.remoteQueryTest(env, jestParams);
|
|
126
153
|
} else if (args.package === "e2e") {
|
|
127
154
|
await this.e2etest(env);
|
|
128
155
|
} else if (args.package) {
|
|
129
156
|
const cwd = "packages/" + args.package;
|
|
130
157
|
await this.do_test("npm", ["run", "test", ...jestParams], env, cwd);
|
|
131
158
|
} else {
|
|
132
|
-
const
|
|
159
|
+
const cwd = ".";
|
|
133
160
|
await this.do_test(
|
|
134
|
-
|
|
135
|
-
["
|
|
136
|
-
env
|
|
161
|
+
"npm",
|
|
162
|
+
["--workspaces", "run", "test", ...jestParams],
|
|
163
|
+
env,
|
|
164
|
+
cwd
|
|
137
165
|
);
|
|
138
166
|
//await this.e2etest(env);
|
|
139
167
|
}
|
package/src/commands/setup.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Set up new saltcorn configuration
|
|
2
3
|
* @category saltcorn-cli
|
|
3
4
|
* @module commands/setup
|
|
4
5
|
*/
|
|
@@ -14,22 +15,32 @@ const { is } = require("contractis");
|
|
|
14
15
|
const path = require("path");
|
|
15
16
|
const fs = require("fs");
|
|
16
17
|
const inquirer = require("inquirer");
|
|
17
|
-
|
|
18
|
+
const tcpPortUsed = require("tcp-port-used");
|
|
18
19
|
const { spawnSync } = require("child_process");
|
|
19
|
-
|
|
20
|
+
const sudo = require("sudo");
|
|
21
|
+
const crypto = require("crypto");
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
24
|
+
* Generate password for user
|
|
23
25
|
* @returns {string}
|
|
24
26
|
*/
|
|
27
|
+
// todo deduplicate code - the same function in User
|
|
25
28
|
const gen_password = () => {
|
|
26
29
|
const s = is.str.generate().replace(" ", "");
|
|
27
30
|
if (s.length > 7) return s;
|
|
28
31
|
else return gen_password();
|
|
29
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Generate jwt secret
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
const genJwtSecret = () => {
|
|
38
|
+
return crypto.randomBytes(64).toString("hex");
|
|
39
|
+
};
|
|
30
40
|
|
|
31
41
|
/**
|
|
32
|
-
*
|
|
42
|
+
* Ask for platform run mode (dev - run manually, server - run as system service)
|
|
43
|
+
*
|
|
33
44
|
* @returns {Promise<object>}
|
|
34
45
|
*/
|
|
35
46
|
const askDevServer = async () => {
|
|
@@ -58,8 +69,8 @@ const askDevServer = async () => {
|
|
|
58
69
|
};
|
|
59
70
|
|
|
60
71
|
/**
|
|
61
|
-
*
|
|
62
|
-
* @param {*} mod
|
|
72
|
+
* Unload module
|
|
73
|
+
* @param {*} mod
|
|
63
74
|
*/
|
|
64
75
|
const unloadModule = (mod) => {
|
|
65
76
|
var name = require.resolve(mod);
|
|
@@ -67,13 +78,19 @@ const unloadModule = (mod) => {
|
|
|
67
78
|
};
|
|
68
79
|
|
|
69
80
|
/**
|
|
81
|
+
* Set up platform run mode (dev - run manually, server - run as system service)
|
|
70
82
|
* @returns {Promise<void>}
|
|
71
83
|
*/
|
|
72
84
|
const setupDevMode = async () => {
|
|
73
85
|
const dbPath = path.join(defaultDataPath, "scdb.sqlite");
|
|
74
86
|
fs.promises.mkdir(defaultDataPath, { recursive: true });
|
|
75
87
|
const session_secret = gen_password();
|
|
76
|
-
|
|
88
|
+
const jwt_secret = genJwtSecret();
|
|
89
|
+
await write_connection_config({
|
|
90
|
+
sqlite_path: dbPath,
|
|
91
|
+
session_secret,
|
|
92
|
+
jwt_secret,
|
|
93
|
+
});
|
|
77
94
|
|
|
78
95
|
if (!fs.existsSync(dbPath)) {
|
|
79
96
|
unloadModule("@saltcorn/data/db");
|
|
@@ -85,6 +102,8 @@ const setupDevMode = async () => {
|
|
|
85
102
|
};
|
|
86
103
|
|
|
87
104
|
/**
|
|
105
|
+
* Check for locally running database (ip 127.0.0.1, port 5432)
|
|
106
|
+
*
|
|
88
107
|
* @returns {Promise<void>}
|
|
89
108
|
*/
|
|
90
109
|
const check_db = async () => {
|
|
@@ -115,8 +134,8 @@ const check_db = async () => {
|
|
|
115
134
|
};
|
|
116
135
|
|
|
117
136
|
/**
|
|
118
|
-
*
|
|
119
|
-
* @param {*} args
|
|
137
|
+
* Execute Linux commands
|
|
138
|
+
* @param {*} args
|
|
120
139
|
* @returns {Promise<void>}
|
|
121
140
|
*/
|
|
122
141
|
const asyncSudo = (args) => {
|
|
@@ -136,8 +155,8 @@ const asyncSudo = (args) => {
|
|
|
136
155
|
};
|
|
137
156
|
|
|
138
157
|
/**
|
|
139
|
-
*
|
|
140
|
-
* @param {*} args
|
|
158
|
+
* Execute Postgres commands
|
|
159
|
+
* @param {*} args
|
|
141
160
|
* @returns {Promise<void>}
|
|
142
161
|
*/
|
|
143
162
|
const asyncSudoPostgres = (args) => {
|
|
@@ -145,8 +164,8 @@ const asyncSudoPostgres = (args) => {
|
|
|
145
164
|
};
|
|
146
165
|
|
|
147
166
|
/**
|
|
148
|
-
*
|
|
149
|
-
* @param {string} for_who
|
|
167
|
+
* Ask for passworf
|
|
168
|
+
* @param {string} for_who
|
|
150
169
|
* @returns {Promise<string>}
|
|
151
170
|
*/
|
|
152
171
|
const get_password = async (for_who) => {
|
|
@@ -163,6 +182,7 @@ const get_password = async (for_who) => {
|
|
|
163
182
|
};
|
|
164
183
|
|
|
165
184
|
/**
|
|
185
|
+
* Install Database
|
|
166
186
|
* @returns {Promise<void>}
|
|
167
187
|
*/
|
|
168
188
|
const install_db = async () => {
|
|
@@ -204,6 +224,7 @@ const install_db = async () => {
|
|
|
204
224
|
`ALTER SCHEMA public OWNER TO ${user};`,
|
|
205
225
|
]);
|
|
206
226
|
const session_secret = await get_password("session secret");
|
|
227
|
+
const jwt_secret = genJwtSecret();
|
|
207
228
|
await write_connection_config({
|
|
208
229
|
host: "localhost",
|
|
209
230
|
port: 5432,
|
|
@@ -211,12 +232,13 @@ const install_db = async () => {
|
|
|
211
232
|
user,
|
|
212
233
|
password: scpass,
|
|
213
234
|
session_secret,
|
|
235
|
+
jwt_secret,
|
|
214
236
|
multi_tenant: false,
|
|
215
237
|
});
|
|
216
238
|
};
|
|
217
239
|
|
|
218
240
|
/**
|
|
219
|
-
*
|
|
241
|
+
* Ask for Database parameters
|
|
220
242
|
* @returns {Promise<object>}
|
|
221
243
|
*/
|
|
222
244
|
const prompt_connection = async () => {
|
|
@@ -236,6 +258,7 @@ const prompt_connection = async () => {
|
|
|
236
258
|
required: true,
|
|
237
259
|
});
|
|
238
260
|
const session_secret = await get_password("session secret");
|
|
261
|
+
const jwt_secret = genJwtSecret();
|
|
239
262
|
return {
|
|
240
263
|
host: host || "localhost",
|
|
241
264
|
port: port || 5432,
|
|
@@ -243,11 +266,13 @@ const prompt_connection = async () => {
|
|
|
243
266
|
user: user || "saltcorn",
|
|
244
267
|
password: password,
|
|
245
268
|
session_secret,
|
|
269
|
+
jwt_secret,
|
|
246
270
|
multi_tenant: false,
|
|
247
271
|
};
|
|
248
272
|
};
|
|
249
273
|
|
|
250
274
|
/**
|
|
275
|
+
* Write platform config
|
|
251
276
|
* @returns {Promise<void>}
|
|
252
277
|
*/
|
|
253
278
|
const setup_connection_config = async () => {
|
|
@@ -256,8 +281,8 @@ const setup_connection_config = async () => {
|
|
|
256
281
|
};
|
|
257
282
|
|
|
258
283
|
/**
|
|
259
|
-
*
|
|
260
|
-
* @param {object} connobj
|
|
284
|
+
*
|
|
285
|
+
* @param {object} connobj
|
|
261
286
|
* @returns {Promise<void>}
|
|
262
287
|
*/
|
|
263
288
|
const write_connection_config = async (connobj) => {
|
|
@@ -290,16 +315,16 @@ const setup_connection = async () => {
|
|
|
290
315
|
};
|
|
291
316
|
|
|
292
317
|
/**
|
|
293
|
-
*
|
|
294
|
-
* @param {object} db
|
|
295
|
-
* @param {string} tblname
|
|
318
|
+
*
|
|
319
|
+
* @param {object} db
|
|
320
|
+
* @param {string} tblname
|
|
296
321
|
* @returns {Promise<boolean>}
|
|
297
322
|
*/
|
|
298
323
|
const table_exists = async (db, tblname) => {
|
|
299
|
-
const { rows } = await db.query(`SELECT EXISTS
|
|
324
|
+
const { rows } = await db.query(`SELECT EXISTS
|
|
300
325
|
(
|
|
301
326
|
SELECT 1
|
|
302
|
-
FROM information_schema.tables
|
|
327
|
+
FROM information_schema.tables
|
|
303
328
|
WHERE table_schema = 'public'
|
|
304
329
|
AND table_name = '${tblname}'
|
|
305
330
|
);`);
|
|
@@ -346,7 +371,7 @@ class SetupCommand extends Command {
|
|
|
346
371
|
* @returns {Promise<void>}
|
|
347
372
|
*/
|
|
348
373
|
async run() {
|
|
349
|
-
console.log("Run
|
|
374
|
+
console.log("Run setup");
|
|
350
375
|
const mode = await askDevServer();
|
|
351
376
|
if (mode == "server") {
|
|
352
377
|
// check if i already know how to connect
|
|
@@ -367,7 +392,7 @@ class SetupCommand extends Command {
|
|
|
367
392
|
*/
|
|
368
393
|
SetupCommand.description = `Set up a new system
|
|
369
394
|
...
|
|
370
|
-
This will attempt to install or connect a database, and set up a
|
|
395
|
+
This will attempt to install or connect a database, and set up a
|
|
371
396
|
configuration file
|
|
372
397
|
`;
|
|
373
398
|
|