@dynamicweb/cli 1.0.0 → 1.0.2
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/bin/commands/env.js +16 -6
- package/bin/commands/files.js +74 -13
- package/bin/commands/install.js +8 -5
- package/bin/commands/login.js +32 -19
- package/bin/index.js +4 -0
- package/bin/utils.js +1 -1
- package/package.json +1 -1
package/bin/commands/env.js
CHANGED
|
@@ -76,10 +76,8 @@ async function handleEnv(argv) {
|
|
|
76
76
|
environment: {
|
|
77
77
|
type: 'input'
|
|
78
78
|
},
|
|
79
|
-
protocol: {
|
|
80
|
-
type: 'input'
|
|
81
|
-
},
|
|
82
79
|
host: {
|
|
80
|
+
describe: 'Enter your host including protocol, i.e "https://yourHost.com":',
|
|
83
81
|
type: 'input'
|
|
84
82
|
},
|
|
85
83
|
interactive: {
|
|
@@ -96,15 +94,26 @@ export async function interactiveEnv(argv, options) {
|
|
|
96
94
|
.then(async (result) => {
|
|
97
95
|
getConfig().env = getConfig().env || {};
|
|
98
96
|
getConfig().env[result.environment] = getConfig().env[result.environment] || {};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
if (result.host) {
|
|
98
|
+
var hostSplit = result.host.split("://");
|
|
99
|
+
if (hostSplit.length == 1) {
|
|
100
|
+
getConfig().env[result.environment].protocol = 'https';
|
|
101
|
+
getConfig().env[result.environment].host = hostSplit[0];
|
|
102
|
+
} else if (hostSplit.length == 2) {
|
|
103
|
+
getConfig().env[result.environment].protocol = hostSplit[0];
|
|
104
|
+
getConfig().env[result.environment].host = hostSplit[1];
|
|
105
|
+
} else {
|
|
106
|
+
console.log(`Issues resolving host ${result.host}`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
102
110
|
if (result.environment) {
|
|
103
111
|
getConfig().current = getConfig().current || {};
|
|
104
112
|
getConfig().current.env = result.environment;
|
|
105
113
|
}
|
|
106
114
|
updateConfig();
|
|
107
115
|
console.log(`Your current environment is now ${getConfig().current.env}`);
|
|
116
|
+
console.log(`To change the host of your environment, use the command 'dw env'`)
|
|
108
117
|
});
|
|
109
118
|
}
|
|
110
119
|
|
|
@@ -118,6 +127,7 @@ async function changeEnv(argv) {
|
|
|
118
127
|
prompt: 'never'
|
|
119
128
|
},
|
|
120
129
|
host: {
|
|
130
|
+
describe: 'Enter your host including protocol, i.e "https://yourHost.com":',
|
|
121
131
|
type: 'input',
|
|
122
132
|
prompt: 'always'
|
|
123
133
|
},
|
package/bin/commands/files.js
CHANGED
|
@@ -28,26 +28,35 @@ export function filesCommand() {
|
|
|
28
28
|
.option('export', {
|
|
29
29
|
alias: 'e',
|
|
30
30
|
type: 'boolean',
|
|
31
|
-
describe: 'Exports the directory at [dirPath] to [outPath]'
|
|
31
|
+
describe: 'Exports the specified directory and all subdirectories at [dirPath] to [outPath]'
|
|
32
32
|
})
|
|
33
33
|
.option('import', {
|
|
34
34
|
alias: 'i',
|
|
35
35
|
type: 'boolean',
|
|
36
36
|
describe: 'Imports the file at [dirPath] to [outPath]'
|
|
37
37
|
})
|
|
38
|
+
.option('overwrite', {
|
|
39
|
+
alias: 'o',
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
describe: 'Used with import, will overwrite existing files at destrination if set to true'
|
|
42
|
+
})
|
|
43
|
+
.option('createEmpty', {
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
describe: 'Used with import, will create a file even if its empty'
|
|
46
|
+
})
|
|
38
47
|
.option('includeFiles', {
|
|
39
48
|
alias: 'f',
|
|
40
49
|
type: 'boolean',
|
|
41
|
-
describe: '
|
|
50
|
+
describe: 'Used with export, includes files in list of directories and files'
|
|
42
51
|
})
|
|
43
52
|
.option('recursive', {
|
|
44
53
|
alias: 'r',
|
|
45
54
|
type: 'boolean',
|
|
46
|
-
describe: '
|
|
55
|
+
describe: 'Used with list, import and export, handles all directories recursively'
|
|
47
56
|
})
|
|
48
57
|
.option('raw', {
|
|
49
58
|
type: 'boolean',
|
|
50
|
-
describe: '
|
|
59
|
+
describe: 'Used with export, keeps zip file instead of unpacking it'
|
|
51
60
|
})
|
|
52
61
|
.option('iamstupid', {
|
|
53
62
|
type: 'boolean',
|
|
@@ -75,11 +84,11 @@ async function handleFiles(argv) {
|
|
|
75
84
|
|
|
76
85
|
if (argv.export) {
|
|
77
86
|
if (argv.dirPath) {
|
|
78
|
-
await download(env, user, argv.dirPath, argv.outPath,
|
|
87
|
+
await download(env, user, argv.dirPath, argv.outPath, true, null, argv.raw, argv.iamstupid, []);
|
|
79
88
|
} else {
|
|
80
89
|
await interactiveConfirm('Are you sure you want a full export of files?', async () => {
|
|
81
90
|
console.log('Full export is starting')
|
|
82
|
-
let filesStructure = (await getFilesStructure(env, user, '/', false,
|
|
91
|
+
let filesStructure = (await getFilesStructure(env, user, '/', false, true)).model;
|
|
83
92
|
let dirs = filesStructure.directories;
|
|
84
93
|
for (let id = 0; id < dirs.length; id++) {
|
|
85
94
|
const dir = dirs[id];
|
|
@@ -91,12 +100,61 @@ async function handleFiles(argv) {
|
|
|
91
100
|
}
|
|
92
101
|
} else if (argv.import) {
|
|
93
102
|
if (argv.dirPath && argv.outPath) {
|
|
94
|
-
let resolvedPath = path.resolve(argv.dirPath)
|
|
95
|
-
|
|
103
|
+
let resolvedPath = path.resolve(argv.dirPath);
|
|
104
|
+
let files;
|
|
105
|
+
if (!argv.overwrite) {
|
|
106
|
+
files = (await getFilesStructure(env, user, argv.outPath, argv.recursive, true)).model;
|
|
107
|
+
}
|
|
108
|
+
if (argv.recursive) {
|
|
109
|
+
await processDirectory(env, user, resolvedPath, argv.outPath, files, resolvedPath, argv.createEmpty, true);
|
|
110
|
+
} else {
|
|
111
|
+
let filesInDir = getFilesInDirectory(resolvedPath);
|
|
112
|
+
if (files)
|
|
113
|
+
filesInDir = getFilesNotInData(filesInDir, files.files.data, resolvedPath);
|
|
114
|
+
await uploadFiles(env, user, filesInDir, argv.outPath, argv.createEmpty);
|
|
115
|
+
}
|
|
96
116
|
}
|
|
97
117
|
}
|
|
98
118
|
}
|
|
99
119
|
|
|
120
|
+
function convertToDataFormat(filePath, resolvedPath) {
|
|
121
|
+
const relativePath = `/Files${filePath.substring(resolvedPath.length)}`;
|
|
122
|
+
return path.format(path.parse(relativePath)).replace(/\\/g, '/');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getFilesNotInData(filesInDir, data, resolvedPath) {
|
|
126
|
+
const existingPaths = data.map(file => file.filePath);
|
|
127
|
+
return filesInDir.filter(filePath => {
|
|
128
|
+
const convertedPath = convertToDataFormat(filePath, resolvedPath);
|
|
129
|
+
return !existingPaths.includes(convertedPath);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getFilesInDirectory(dirPath) {
|
|
134
|
+
return fs.readdirSync(dirPath)
|
|
135
|
+
.map(file => path.join(dirPath, file))
|
|
136
|
+
.filter(file => fs.statSync(file).isFile());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function processDirectory(env, user, dirPath, outPath, files, originalDir, createEmpty, isRoot = false) {
|
|
140
|
+
let filesInDir = getFilesInDirectory(dirPath);
|
|
141
|
+
let missingFiles;
|
|
142
|
+
if (files === undefined)
|
|
143
|
+
missingFiles = filesInDir;
|
|
144
|
+
else
|
|
145
|
+
missingFiles = getFilesNotInData(filesInDir, files.files.data, originalDir);
|
|
146
|
+
if (missingFiles.length > 0)
|
|
147
|
+
await uploadFiles(env, user, missingFiles, isRoot ? outPath : path.join(outPath, path.basename(dirPath)), createEmpty);
|
|
148
|
+
|
|
149
|
+
const subDirectories = fs.readdirSync(dirPath)
|
|
150
|
+
.map(subDir => path.join(dirPath, subDir))
|
|
151
|
+
.filter(subDir => fs.statSync(subDir).isDirectory());
|
|
152
|
+
for (let subDir of subDirectories) {
|
|
153
|
+
const remoteSubDir = files?.directories.find(dir => dir.name === path.basename(subDir));
|
|
154
|
+
await processDirectory(env, user, subDir, isRoot ? outPath : path.join(outPath, path.basename(dirPath)), remoteSubDir, originalDir, createEmpty);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
100
158
|
function resolveTree(dirs, indentLevel, parentHasFiles) {
|
|
101
159
|
let end = `└──`
|
|
102
160
|
let mid = `├──`
|
|
@@ -208,12 +266,15 @@ async function getFilesStructure(env, user, dirPath, recursive, includeFiles) {
|
|
|
208
266
|
}
|
|
209
267
|
}
|
|
210
268
|
|
|
211
|
-
export async function
|
|
212
|
-
console.log('Uploading
|
|
269
|
+
export async function uploadFiles(env, user, localFilePaths, destinationPath, createEmpty = false) {
|
|
270
|
+
console.log('Uploading files')
|
|
213
271
|
let form = new FormData();
|
|
214
272
|
form.append('path', destinationPath);
|
|
215
|
-
|
|
216
|
-
|
|
273
|
+
localFilePaths.forEach((localPath, index) => {
|
|
274
|
+
console.log(localPath)
|
|
275
|
+
form.append('files', fs.createReadStream(path.resolve(localPath)));
|
|
276
|
+
});
|
|
277
|
+
let res = await fetch(`${env.protocol}://${env.host}/Admin/Api/Upload?` + new URLSearchParams({"createEmptyFiles": createEmpty}), {
|
|
217
278
|
method: 'POST',
|
|
218
279
|
body: form,
|
|
219
280
|
headers: {
|
|
@@ -223,7 +284,7 @@ export async function uploadFile(env, user, localFilePath, destinationPath) {
|
|
|
223
284
|
});
|
|
224
285
|
if (res.ok) {
|
|
225
286
|
if (env.verbose) console.log(await res.json())
|
|
226
|
-
console.log(`
|
|
287
|
+
console.log(`Files uploaded`)
|
|
227
288
|
}
|
|
228
289
|
else {
|
|
229
290
|
console.log(res)
|
package/bin/commands/install.js
CHANGED
|
@@ -2,7 +2,7 @@ import fetch from 'node-fetch';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { setupEnv, getAgent } from './env.js';
|
|
4
4
|
import { setupUser } from './login.js';
|
|
5
|
-
import {
|
|
5
|
+
import { uploadFiles } from './files.js';
|
|
6
6
|
|
|
7
7
|
export function installCommand() {
|
|
8
8
|
return {
|
|
@@ -25,15 +25,17 @@ async function handleInstall(argv) {
|
|
|
25
25
|
let env = await setupEnv(argv);
|
|
26
26
|
let user = await setupUser(argv, env);
|
|
27
27
|
let resolvedPath = path.resolve(argv.filePath)
|
|
28
|
-
await
|
|
28
|
+
await uploadFiles(env, user, [resolvedPath], 'System/AddIns/Local');
|
|
29
29
|
await installAddin(env, user, resolvedPath)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async function installAddin(env, user, resolvedPath) {
|
|
33
33
|
console.log('Installing addin')
|
|
34
|
+
let filename = path.basename(resolvedPath);
|
|
34
35
|
let data = {
|
|
35
|
-
'
|
|
36
|
-
|
|
36
|
+
'Ids': [
|
|
37
|
+
`${filename.substring(0, filename.lastIndexOf('.')) || filename}|${path.extname(resolvedPath)}`
|
|
38
|
+
]
|
|
37
39
|
}
|
|
38
40
|
let res = await fetch(`${env.protocol}://${env.host}/Admin/Api/AddinInstall`, {
|
|
39
41
|
method: 'POST',
|
|
@@ -50,6 +52,7 @@ async function installAddin(env, user, resolvedPath) {
|
|
|
50
52
|
console.log(`Addin installed`)
|
|
51
53
|
}
|
|
52
54
|
else {
|
|
53
|
-
console.log(
|
|
55
|
+
console.log('Request failed, returned error:')
|
|
56
|
+
console.log(await res.json())
|
|
54
57
|
}
|
|
55
58
|
}
|
package/bin/commands/login.js
CHANGED
|
@@ -70,7 +70,7 @@ export async function interactiveLogin(argv, options) {
|
|
|
70
70
|
.interactive(options)
|
|
71
71
|
.then(async (result) => {
|
|
72
72
|
if (!getConfig().env || !getConfig().env[result.environment] || !getConfig().env[result.environment].host || !getConfig().env[result.environment].protocol) {
|
|
73
|
-
if (!argv.host
|
|
73
|
+
if (!argv.host)
|
|
74
74
|
console.log(`The environment specified is missing parameters, please specify them`)
|
|
75
75
|
await interactiveEnv(argv, {
|
|
76
76
|
environment: {
|
|
@@ -78,11 +78,8 @@ export async function interactiveLogin(argv, options) {
|
|
|
78
78
|
default: result.environment,
|
|
79
79
|
prompt: 'never'
|
|
80
80
|
},
|
|
81
|
-
protocol: {
|
|
82
|
-
type: 'input',
|
|
83
|
-
prompt: 'if-no-arg'
|
|
84
|
-
},
|
|
85
81
|
host: {
|
|
82
|
+
describe: 'Enter your host including protocol, i.e "https://yourHost.com":',
|
|
86
83
|
type: 'input',
|
|
87
84
|
prompt: 'if-no-arg'
|
|
88
85
|
},
|
|
@@ -91,14 +88,16 @@ export async function interactiveLogin(argv, options) {
|
|
|
91
88
|
}
|
|
92
89
|
})
|
|
93
90
|
}
|
|
94
|
-
await loginInteractive(result);
|
|
91
|
+
await loginInteractive(result, argv.verbose);
|
|
95
92
|
});
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
async function loginInteractive(result) {
|
|
95
|
+
async function loginInteractive(result, verbose) {
|
|
99
96
|
var protocol = getConfig().env[result.environment].protocol;
|
|
100
|
-
var token = await login(result.username, result.password, result.environment, protocol);
|
|
101
|
-
|
|
97
|
+
var token = await login(result.username, result.password, result.environment, protocol, verbose);
|
|
98
|
+
if (!token) return;
|
|
99
|
+
var apiKey = await getApiKey(token, result.environment, protocol, verbose)
|
|
100
|
+
if (!apiKey) return;
|
|
102
101
|
getConfig().env = getConfig().env || {};
|
|
103
102
|
getConfig().env[result.environment].users = getConfig().env[result.environment].users || {};
|
|
104
103
|
getConfig().env[result.environment].users[result.username] = getConfig().env[result.environment].users[result.username] || {};
|
|
@@ -108,7 +107,7 @@ async function loginInteractive(result) {
|
|
|
108
107
|
updateConfig();
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
async function login(username, password, env, protocol) {
|
|
110
|
+
async function login(username, password, env, protocol, verbose) {
|
|
112
111
|
let data = new URLSearchParams();
|
|
113
112
|
data.append('Username', username);
|
|
114
113
|
data.append('Password', password);
|
|
@@ -123,16 +122,21 @@ async function login(username, password, env, protocol) {
|
|
|
123
122
|
|
|
124
123
|
if (res.ok) {
|
|
125
124
|
let user = parseCookies(res.headers.get('set-cookie')).user;
|
|
126
|
-
|
|
125
|
+
if (!user) return;
|
|
126
|
+
return await getToken(user, env, protocol, verbose)
|
|
127
127
|
}
|
|
128
128
|
else {
|
|
129
|
-
console.
|
|
129
|
+
if (verbose) console.info(res)
|
|
130
|
+
console.log(`Login attempt failed with username ${username}, please verify its a valid user in your Dynamicweb solution.`)
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
function parseCookies (cookieHeader) {
|
|
134
135
|
const list = {};
|
|
135
|
-
if (!cookieHeader)
|
|
136
|
+
if (!cookieHeader) {
|
|
137
|
+
console.log(`Could not get the necessary information from the login request, please verify its a valid user in your Dynamicweb solution.`)
|
|
138
|
+
return list;
|
|
139
|
+
}
|
|
136
140
|
|
|
137
141
|
cookieHeader.replace('httponly, ', '').replace('Dynamicweb.Admin', 'user').split(`;`).forEach(cookie => {
|
|
138
142
|
let [ name, ...rest] = cookie.split(`=`);
|
|
@@ -143,11 +147,15 @@ function parseCookies (cookieHeader) {
|
|
|
143
147
|
list[name] = decodeURIComponent(value);
|
|
144
148
|
});
|
|
145
149
|
|
|
150
|
+
if (!list.user) {
|
|
151
|
+
console.log(`Could not get the necessary information from the login request, please verify its a valid user in your Dynamicweb solution.`)
|
|
152
|
+
}
|
|
153
|
+
|
|
146
154
|
return list;
|
|
147
155
|
}
|
|
148
156
|
|
|
149
|
-
async function getToken(user, env, protocol) {
|
|
150
|
-
var res = await fetch(`${
|
|
157
|
+
async function getToken(user, env, protocol, verbose) {
|
|
158
|
+
var res = await fetch(`${protocol}://${getConfig().env[env].host}/Admin/Authentication/Token`, {
|
|
151
159
|
method: 'GET',
|
|
152
160
|
headers: {
|
|
153
161
|
'cookie': `Dynamicweb.Admin=${user}`
|
|
@@ -157,12 +165,16 @@ async function getToken(user, env, protocol) {
|
|
|
157
165
|
if (res.ok) {
|
|
158
166
|
return (await res.json()).token
|
|
159
167
|
}
|
|
168
|
+
else {
|
|
169
|
+
if (verbose) console.info(res)
|
|
170
|
+
console.log(`Could not fetch the token for the logged in user ${user}, please verify its a valid user in your Dynamicweb solution.`)
|
|
171
|
+
}
|
|
160
172
|
}
|
|
161
173
|
|
|
162
|
-
async function getApiKey(token, env, protocol) {
|
|
174
|
+
async function getApiKey(token, env, protocol, verbose) {
|
|
163
175
|
let data = {
|
|
164
|
-
'Name': '
|
|
165
|
-
'Prefix': '
|
|
176
|
+
'Name': 'DW CLI',
|
|
177
|
+
'Prefix': 'CLI',
|
|
166
178
|
'Description': 'Auto-generated ApiKey by DW CLI'
|
|
167
179
|
};
|
|
168
180
|
var res = await fetch(`${protocol}://${getConfig().env[env].host}/Admin/Api/ApiKeySave`, {
|
|
@@ -179,7 +191,8 @@ async function getApiKey(token, env, protocol) {
|
|
|
179
191
|
return (await res.json()).message
|
|
180
192
|
}
|
|
181
193
|
else {
|
|
182
|
-
console.
|
|
194
|
+
if (verbose) console.info(res)
|
|
195
|
+
console.log(`Could not create an API Key for the logged in user, please verify its a valid user in your Dynamicweb solution.`)
|
|
183
196
|
}
|
|
184
197
|
}
|
|
185
198
|
|
package/bin/index.js
CHANGED
|
@@ -39,6 +39,10 @@ function baseCommand() {
|
|
|
39
39
|
command: '$0',
|
|
40
40
|
describe: 'Shows the current env and user being used',
|
|
41
41
|
handler: () => {
|
|
42
|
+
if (Object.keys(getConfig()).length === 0) {
|
|
43
|
+
console.log('To login to a solution use `dw login`')
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
42
46
|
console.log(`Environment: ${getConfig()?.current?.env}`)
|
|
43
47
|
console.log(`User: ${getConfig()?.env[getConfig()?.current?.env]?.current?.user}`)
|
|
44
48
|
console.log(`Protocol: ${getConfig()?.env[getConfig()?.current?.env]?.protocol}`)
|
package/bin/utils.js
CHANGED
package/package.json
CHANGED