cht-conf 3.10.0 → 3.11.0
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/.eslintignore +2 -1
- package/.releaserc.json +1 -1
- package/CHANGELOG.md +22 -1
- package/README.md +3 -1
- package/package.json +7 -3
- package/release-notes.md +1 -1
- package/src/bin/index.js +14 -12
- package/src/cli/check-node-version.js +9 -7
- package/src/cli/shell-completion-setup.js +5 -8
- package/src/fn/check-git.js +3 -5
- package/src/fn/compile-app-settings.js +25 -8
- package/src/fn/compress-images.js +1 -0
- package/src/fn/compress-svgs.js +1 -1
- package/src/fn/convert-app-forms.js +13 -6
- package/src/fn/convert-collect-forms.js +11 -4
- package/src/fn/convert-contact-forms.js +62 -59
- package/src/fn/create-users.js +4 -7
- package/src/fn/delete-forms.js +17 -16
- package/src/fn/move-contacts.js +2 -3
- package/src/fn/upload-app-forms.js +11 -4
- package/src/fn/upload-app-settings.js +28 -22
- package/src/fn/upload-collect-forms.js +10 -5
- package/src/fn/upload-contact-forms.js +13 -6
- package/src/fn/upload-custom-translations.js +9 -8
- package/src/fn/upload-docs.js +3 -4
- package/src/fn/upload-resources.js +6 -2
- package/src/fn/watch-project.js +271 -0
- package/src/lib/api.js +13 -14
- package/src/lib/convert-forms.js +46 -31
- package/src/lib/git-exec.js +1 -1
- package/src/lib/main.js +16 -22
- package/src/lib/project-paths.js +12 -0
- package/src/lib/upload-forms.js +36 -6
- package/src/lib/validate-app-settings.js +2 -2
package/.eslintignore
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
**/build
|
|
1
|
+
**/build
|
|
2
|
+
test/data/**
|
package/.releaserc.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [3.11.0](https://github.com/medic/cht-conf/compare/v3.10.2...v3.11.0) (2022-04-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **#477:** adds watch-project action ([7a3efc5](https://github.com/medic/cht-conf/commit/7a3efc5efcbd98d8a6b03e801945201ed17ac00f)), closes [#477](https://github.com/medic/cht-conf/issues/477)
|
|
7
|
+
|
|
8
|
+
## [3.10.2](https://github.com/medic/cht-conf/compare/v3.10.1...v3.10.2) (2022-03-29)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **#371:** allow more characters in form name validation ([265bc48](https://github.com/medic/cht-conf/commit/265bc487d38201e4b3a96ee3d8939c7cba97b5a2)), closes [#371](https://github.com/medic/cht-conf/issues/371) [medic/cht-conf#471](https://github.com/medic/cht-conf/issues/471)
|
|
14
|
+
|
|
15
|
+
## [3.10.1](https://github.com/medic/cht-conf/compare/v3.10.0...v3.10.1) (2022-02-23)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **#465:** remove process.exit and extraneous require ([058e651](https://github.com/medic/cht-conf/commit/058e65182928cdefdd5bb8fb41849fb9b5164631)), closes [#465](https://github.com/medic/cht-conf/issues/465)
|
|
21
|
+
|
|
1
22
|
# [3.10.0](https://github.com/medic/cht-conf/compare/v3.9.5...v3.10.0) (2022-02-02)
|
|
2
23
|
|
|
3
24
|
|
|
@@ -185,7 +206,7 @@ As of this release no docs on the server will be touched unless some configurati
|
|
|
185
206
|
|
|
186
207
|
### New action to bulk-edit contacts
|
|
187
208
|
|
|
188
|
-
You can now bulk edit contacts at once by providing a CSV. For more information, read [the documentation](https://github.com/medic/cht-conf/blob/
|
|
209
|
+
You can now bulk edit contacts at once by providing a CSV. For more information, read [the documentation](https://github.com/medic/cht-conf/blob/main/README.md#editing-contacts-across-the-hierarchy).
|
|
189
210
|
|
|
190
211
|
[#297](https://github.com/medic/cht-conf/issues/297)
|
|
191
212
|
|
package/README.md
CHANGED
|
@@ -91,6 +91,8 @@ If a different username is required, add the `--user` switch:
|
|
|
91
91
|
|
|
92
92
|
cht --url=https://username:password@example.com:12345
|
|
93
93
|
|
|
94
|
+
**NB** - When specifying the URL with `--url`, be sure not to specify the CouchDB database name in the URL. The CHT API will find the correct database.
|
|
95
|
+
|
|
94
96
|
### Into an archive to be uploaded later
|
|
95
97
|
|
|
96
98
|
cht --archive
|
|
@@ -315,7 +317,7 @@ Breaking| perf(#2): remove reporting rates feature <br/> BREAKING CHANGE: report
|
|
|
315
317
|
|
|
316
318
|
### Releasing betas
|
|
317
319
|
|
|
318
|
-
1. Checkout `
|
|
320
|
+
1. Checkout the default branch, for example `main`
|
|
319
321
|
1. Run `npm version --no-git-tag-version <major>.<minor>.<patch>-beta.1`. This will only update the versions in `package.json` and `package-lock.json`. It will not create a git tag and not create an associated commit.
|
|
320
322
|
1. Run `npm publish --tag beta`. This will publish your beta tag to npm's beta channel.
|
|
321
323
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cht-conf",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "Configure CHT deployments",
|
|
5
5
|
"main": "./src/lib/main.js",
|
|
6
6
|
"engines": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"clean": "rm -rf ./build/",
|
|
11
|
-
"eslint": "eslint src/**/*.js test/*.js test/**/*.js",
|
|
11
|
+
"eslint": "eslint 'src/**/*.js' test/*.js 'test/**/*.js'",
|
|
12
12
|
"docker-start-couchdb": "npm run docker-stop-couchdb && docker run -d -p 6984:5984 --rm --name cht-conf-couchdb couchdb:2.3.1 && sh test/scripts/wait_for_response_code.sh 6984 200 CouchDB",
|
|
13
13
|
"docker-stop-couchdb": "docker stop cht-conf-couchdb || true",
|
|
14
14
|
"test": "npm run eslint && npm run docker-start-couchdb && npm run clean && mkdir -p build/test && cp -r test/data build/test/data && cd build/test && nyc --reporter=html mocha --forbid-only ../../test/**/*.spec.js && cd ../.. && npm run docker-stop-couchdb",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@hapi/joi": "^16.1.8",
|
|
39
39
|
"@medic/translation-checker": "^1.0.1",
|
|
40
|
+
"@parcel/watcher": "^2.0.5",
|
|
40
41
|
"canonical-json": "0.0.4",
|
|
41
42
|
"csv-parse": "^4.16.0",
|
|
42
43
|
"dom-compare": "^0.6.0",
|
|
@@ -56,12 +57,14 @@
|
|
|
56
57
|
"pouchdb-core": "^7.2.2",
|
|
57
58
|
"pouchdb-mapreduce": "^7.2.2",
|
|
58
59
|
"properties": "^1.2.1",
|
|
60
|
+
"queue-promise": "^2.2.1",
|
|
59
61
|
"readline-sync": "^1.4.10",
|
|
60
62
|
"redact-basic-auth": "^1.0.1",
|
|
61
63
|
"request": "^2.88.2",
|
|
62
64
|
"request-promise-native": "^1.0.9",
|
|
63
65
|
"semver": "^6.1.1",
|
|
64
66
|
"svgo": "^1.3.2",
|
|
67
|
+
"terser-webpack-plugin": "^1.4.3",
|
|
65
68
|
"uuid": "^8.3.2",
|
|
66
69
|
"webpack": "^4.46.0",
|
|
67
70
|
"xmldom": "^0.6.0"
|
|
@@ -85,6 +88,7 @@
|
|
|
85
88
|
"pouchdb-adapter-memory": "^7.2.2",
|
|
86
89
|
"rewire": "^5.0.0",
|
|
87
90
|
"semantic-release": "^18.0.0",
|
|
88
|
-
"sinon": "^7.3.2"
|
|
91
|
+
"sinon": "^7.3.2",
|
|
92
|
+
"fs-extra": "8.1.0"
|
|
89
93
|
}
|
|
90
94
|
}
|
package/release-notes.md
CHANGED
|
@@ -134,7 +134,7 @@ As of this release no docs on the server will be touched unless some configurati
|
|
|
134
134
|
|
|
135
135
|
### New action to bulk-edit contacts
|
|
136
136
|
|
|
137
|
-
You can now bulk edit contacts at once by providing a CSV. For more information, read [the documentation](https://github.com/medic/cht-conf/blob/
|
|
137
|
+
You can now bulk edit contacts at once by providing a CSV. For more information, read [the documentation](https://github.com/medic/cht-conf/blob/main/README.md#editing-contacts-across-the-hierarchy).
|
|
138
138
|
|
|
139
139
|
[#297](https://github.com/medic/cht-conf/issues/297)
|
|
140
140
|
|
package/src/bin/index.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { error } = require('../lib/log');
|
|
4
|
-
require('../cli/check-node-version');
|
|
3
|
+
const { info, error } = require('../lib/log');
|
|
4
|
+
const checkNodeVersion = require('../cli/check-node-version');
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
try {
|
|
7
|
+
checkNodeVersion();
|
|
8
|
+
} catch (e) {
|
|
9
|
+
error(e.message);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
7
12
|
|
|
13
|
+
const main = require('../lib/main');
|
|
8
14
|
(async () => {
|
|
9
|
-
let returnCode;
|
|
10
15
|
try {
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
error(e);
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
finally {
|
|
18
|
-
process.exit(returnCode);
|
|
16
|
+
await main(process.argv, process.env);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
info(e); // log the details for debugging
|
|
19
|
+
error(e.message); // error the message to make it clear
|
|
20
|
+
process.exitCode = 1; // emit a non-zero exit code for scripting
|
|
19
21
|
}
|
|
20
22
|
})();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const MIN_NODE_VERSION = 6;
|
|
2
2
|
const currentNodeVersion = process.versions.node;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
module.exports = () => {
|
|
5
|
+
const currentMajor = process.versions.node.split('.')[0];
|
|
6
|
+
if(Number.parseInt(currentMajor) < MIN_NODE_VERSION) {
|
|
7
|
+
throw new Error(`Your NodeJS is too old.
|
|
8
|
+
You are running node version: ${currentNodeVersion}
|
|
9
|
+
cht-conf requires version: ${MIN_NODE_VERSION}
|
|
10
|
+
Please upgrade node to continue.`);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
const fs = require('../lib/sync-fs');
|
|
2
|
-
const { error } = require('../lib/log');
|
|
3
2
|
|
|
4
|
-
const
|
|
3
|
+
const SUPPORTED_SHELLS = ['bash'];
|
|
5
4
|
|
|
6
5
|
module.exports = shell => {
|
|
7
|
-
|
|
8
|
-
if (supported_shells.includes(shell)){
|
|
6
|
+
if (SUPPORTED_SHELLS.includes(shell)){
|
|
9
7
|
const completionFile = `${__dirname}/shell-completion.${shell}`;
|
|
10
8
|
if (fs.exists(completionFile)){
|
|
11
9
|
console.log(fs.read(completionFile));
|
|
12
|
-
|
|
10
|
+
return;
|
|
13
11
|
}
|
|
14
12
|
} else if (shell === true){
|
|
15
|
-
|
|
13
|
+
throw new Error('shell type argument not specified e.g. --shell-completion=bash');
|
|
16
14
|
} else {
|
|
17
|
-
|
|
15
|
+
throw new Error(`completion not yet supported for '${shell}' shell`);
|
|
18
16
|
}
|
|
19
|
-
process.exit(1);
|
|
20
17
|
};
|
package/src/fn/check-git.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const git = require('../lib/git-exec');
|
|
2
|
-
const { info, warn
|
|
2
|
+
const { info, warn } = require('../lib/log');
|
|
3
3
|
const userPrompt = require('../lib/user-prompt');
|
|
4
4
|
const environment = require('../lib/environment');
|
|
5
5
|
|
|
@@ -17,8 +17,7 @@ module.exports = {
|
|
|
17
17
|
'not staged for commit.');
|
|
18
18
|
warn('Changes untracked or to be committed:\n' + status);
|
|
19
19
|
if (!userPrompt.keyInYN('Are you sure you want to continue?')) {
|
|
20
|
-
|
|
21
|
-
process.exit(1);
|
|
20
|
+
throw new Error('User aborted execution.');
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
info('Fetching git upstream...');
|
|
@@ -26,8 +25,7 @@ module.exports = {
|
|
|
26
25
|
if (syncStatus) {
|
|
27
26
|
warn(syncStatus);
|
|
28
27
|
if (!userPrompt.keyInYN('Are you sure you want to continue?')) {
|
|
29
|
-
|
|
30
|
-
process.exit(1);
|
|
28
|
+
throw new Error('User aborted execution.');
|
|
31
29
|
}
|
|
32
30
|
}
|
|
33
31
|
}
|
|
@@ -8,6 +8,21 @@ const parseTargets = require('../lib/parse-targets');
|
|
|
8
8
|
const { warn } = require('../lib/log');
|
|
9
9
|
const parsePurge = require('../lib/parse-purge');
|
|
10
10
|
const validateAppSettings = require('../lib/validate-app-settings');
|
|
11
|
+
const { APP_SETTINGS_DIR_PATH, APP_SETTINGS_JSON_PATH } = require('../lib/project-paths');
|
|
12
|
+
|
|
13
|
+
// we can't used named capture groups yet
|
|
14
|
+
const JS_FILE_MATCHER = /^(.+)(\.js)$/; // 2 groups get the file name and extension
|
|
15
|
+
const JSON_FILE_MATCHER = /^(.+)(\.json)$/;
|
|
16
|
+
const configFileMatcher = (fileName) => {
|
|
17
|
+
const jsFileMatchResult = fileName.match(JS_FILE_MATCHER);
|
|
18
|
+
// the first element is always the whole matched string, then our first file name group
|
|
19
|
+
if (jsFileMatchResult) return jsFileMatchResult[1];
|
|
20
|
+
|
|
21
|
+
const jsonFileMatchResult = fileName.match(JSON_FILE_MATCHER);
|
|
22
|
+
if (jsonFileMatchResult) return jsonFileMatchResult[1];
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
11
26
|
|
|
12
27
|
const compileAppSettings = async () => {
|
|
13
28
|
const options = parseExtraArgs(environment.extraArgs);
|
|
@@ -23,7 +38,7 @@ const compileAppSettings = async () => {
|
|
|
23
38
|
appSettings = await compileAppSettingsForProject(projectDir, options);
|
|
24
39
|
}
|
|
25
40
|
|
|
26
|
-
fs.writeJson(path.join(projectDir,
|
|
41
|
+
fs.writeJson(path.join(projectDir, APP_SETTINGS_JSON_PATH), appSettings);
|
|
27
42
|
};
|
|
28
43
|
|
|
29
44
|
const compileAppSettingsForProject = async (projectDir, options) => {
|
|
@@ -41,8 +56,8 @@ const compileAppSettingsForProject = async (projectDir, options) => {
|
|
|
41
56
|
|
|
42
57
|
const readOptionalJson = path => fs.exists(path) ? fs.readJson(path) : undefined;
|
|
43
58
|
let appSettings;
|
|
44
|
-
const baseSettingsPath = path.join(projectDir,
|
|
45
|
-
const appSettingsPath = path.join(projectDir,
|
|
59
|
+
const baseSettingsPath = path.join(projectDir, `${APP_SETTINGS_DIR_PATH}/base_settings.json`);
|
|
60
|
+
const appSettingsPath = path.join(projectDir, APP_SETTINGS_JSON_PATH);
|
|
46
61
|
const esLintFilePath = path.join(projectDir, '.eslintrc');
|
|
47
62
|
|
|
48
63
|
// Fail if no eslintrc file is found
|
|
@@ -56,10 +71,10 @@ const compileAppSettingsForProject = async (projectDir, options) => {
|
|
|
56
71
|
if (fs.exists(baseSettingsPath)) {
|
|
57
72
|
// using modular config so should override anything already defined in app_settings.json
|
|
58
73
|
appSettings = fs.readJson(baseSettingsPath);
|
|
59
|
-
if(appSettings.forms) {
|
|
74
|
+
if (appSettings.forms) {
|
|
60
75
|
warn('forms should be defined in a separate <config_repo>/app_settings/forms.json file.');
|
|
61
76
|
}
|
|
62
|
-
if(appSettings.schedules) {
|
|
77
|
+
if (appSettings.schedules) {
|
|
63
78
|
warn('schedules should be defined in a separate <config_repo>/app_settings/schedules.json file.');
|
|
64
79
|
}
|
|
65
80
|
const formSettings = readOptionalJson(path.join(projectDir, 'app_settings/forms.json'));
|
|
@@ -107,7 +122,7 @@ function applyTransforms(app_settings, inherited) {
|
|
|
107
122
|
rules.forEach(k => {
|
|
108
123
|
const parts = k.split('.');
|
|
109
124
|
let t = target;
|
|
110
|
-
while(parts.length > 1) {
|
|
125
|
+
while (parts.length > 1) {
|
|
111
126
|
t = t[parts[0]];
|
|
112
127
|
parts.shift();
|
|
113
128
|
}
|
|
@@ -122,7 +137,7 @@ function applyTransforms(app_settings, inherited) {
|
|
|
122
137
|
.forEach(k => {
|
|
123
138
|
const parts = k.split('.');
|
|
124
139
|
let t = target;
|
|
125
|
-
while(parts.length > 1) {
|
|
140
|
+
while (parts.length > 1) {
|
|
126
141
|
t = t[parts[0]];
|
|
127
142
|
parts.shift();
|
|
128
143
|
}
|
|
@@ -146,7 +161,7 @@ function applyTransforms(app_settings, inherited) {
|
|
|
146
161
|
.forEach(k => {
|
|
147
162
|
const parts = k.split('.');
|
|
148
163
|
let t = target;
|
|
149
|
-
while(parts.length > 1) {
|
|
164
|
+
while (parts.length > 1) {
|
|
150
165
|
t = t[parts[0]];
|
|
151
166
|
parts.shift();
|
|
152
167
|
}
|
|
@@ -178,5 +193,7 @@ const parseExtraArgs = (extraArgs = []) => {
|
|
|
178
193
|
|
|
179
194
|
module.exports = {
|
|
180
195
|
requiresInstance: false,
|
|
196
|
+
APP_SETTINGS_DIR_PATH,
|
|
197
|
+
configFileMatcher,
|
|
181
198
|
execute: compileAppSettings
|
|
182
199
|
};
|
package/src/fn/compress-svgs.js
CHANGED
|
@@ -16,6 +16,6 @@ module.exports = {
|
|
|
16
16
|
.then(() => svgo.optimize(fs.read(path), { path }))
|
|
17
17
|
.then(result => fs.write(path, result.data))
|
|
18
18
|
.then(() => trace('Compressed', path))
|
|
19
|
-
.then(() => warn('Make sure you compare the content of your SVG files before merging to the
|
|
19
|
+
.then(() => warn('Make sure you compare the content of your SVG files before merging to the default branch - sometimes optimising can change their contents!')),
|
|
20
20
|
Promise.resolve())
|
|
21
21
|
};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
const convertForms = require('../lib/convert-forms');
|
|
1
|
+
const convertForms = require('../lib/convert-forms').execute;
|
|
2
2
|
const environment = require('../lib/environment');
|
|
3
|
+
const { APP_FORMS_PATH } = require('../lib/project-paths');
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
execute: () => convertForms(environment.pathToProject, 'app', {
|
|
5
|
+
const convertAppForms = (forms) => {
|
|
6
|
+
return convertForms(environment.pathToProject, 'app', {
|
|
7
7
|
enketo: true,
|
|
8
|
-
forms:
|
|
8
|
+
forms: forms,
|
|
9
9
|
transformer: xml => xml.replace('</instance>', '</instance>\n <instance id="contact-summary"/>'),
|
|
10
|
-
})
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
requiresInstance: false,
|
|
15
|
+
convertAppForms,
|
|
16
|
+
APP_FORMS_PATH,
|
|
17
|
+
execute: () => convertAppForms(environment.extraArgs)
|
|
11
18
|
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
const convertForms = require('../lib/convert-forms');
|
|
1
|
+
const convertForms = require('../lib/convert-forms').execute;
|
|
2
2
|
const environment = require('../lib/environment');
|
|
3
|
+
const { COLLECT_FORMS_PATH } = require('../lib/project-paths');
|
|
4
|
+
|
|
5
|
+
const convertCollectForms = (forms) => {
|
|
6
|
+
return convertForms(environment.pathToProject, 'collect', {
|
|
7
|
+
forms: forms,
|
|
8
|
+
});
|
|
9
|
+
};
|
|
3
10
|
|
|
4
11
|
module.exports = {
|
|
5
12
|
requiresInstance: false,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
COLLECT_FORMS_PATH,
|
|
14
|
+
convertCollectForms,
|
|
15
|
+
execute: () => convertCollectForms(environment.extraArgs)
|
|
9
16
|
};
|
|
@@ -1,92 +1,95 @@
|
|
|
1
|
-
const convertForms = require('../lib/convert-forms');
|
|
1
|
+
const convertForms = require('../lib/convert-forms').execute;
|
|
2
2
|
const environment = require('../lib/environment');
|
|
3
3
|
const fs = require('../lib/sync-fs');
|
|
4
|
+
const { CONTACT_FORMS_PATH } = require('../lib/project-paths');
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
const dir = `${environment.pathToProject}
|
|
6
|
+
const convertContactForm = (forms) => {
|
|
7
|
+
const dir = `${environment.pathToProject}/${CONTACT_FORMS_PATH}`;
|
|
7
8
|
const placeTypesJson = `${dir}/place-types.json`;
|
|
8
9
|
|
|
9
10
|
let PLACE_TYPES;
|
|
10
|
-
if(fs.exists(placeTypesJson)) {
|
|
11
|
+
if (fs.exists(placeTypesJson)) {
|
|
11
12
|
PLACE_TYPES = fs.readJson(placeTypesJson);
|
|
12
13
|
Object.keys(PLACE_TYPES)
|
|
13
14
|
.forEach(type => {
|
|
14
|
-
fs.copy(`${dir}/PLACE_TYPE-create.xlsx`, `${dir}/${type}-create.xlsx`,{ overwrite: false });
|
|
15
|
+
fs.copy(`${dir}/PLACE_TYPE-create.xlsx`, `${dir}/${type}-create.xlsx`, { overwrite: false });
|
|
15
16
|
fs.copy(`${dir}/PLACE_TYPE-edit.xlsx`, `${dir}/${type}-edit.xlsx`, { overwrite: false });
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
return convertForms(environment.pathToProject, 'contact', {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
enketo: true,
|
|
22
|
+
force_data_node: 'data',
|
|
23
|
+
forms: forms,
|
|
24
|
+
transformer: (xml, path) => {
|
|
25
|
+
const type = path.replace(/.*\/(.*?)(-(create|edit))?\.xml/, '$1');
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
if (PLACE_TYPES) {
|
|
28
|
+
xml = xml
|
|
29
|
+
.replace(/PLACE_TYPE/g, type)
|
|
30
|
+
.replace(/PLACE_NAME/g, PLACE_TYPES[type]);
|
|
31
|
+
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
// The ordering of elements in the <model> has an arcane affect on the
|
|
34
|
+
// order that docs are saved in the database when processing a form.
|
|
35
|
+
// Move the main doc's element down to the bottom.
|
|
36
|
+
// For templated PLACE_TYPE forms, shifting must be done _after_ templating.
|
|
37
|
+
if (xml.includes('</inputs>')) {
|
|
38
|
+
let matchedBlock;
|
|
39
|
+
const matcher = new RegExp(`\\s*<${type}>[\\s\\S]*</${type}>\\s*(\\r|\\n)`);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
xml = xml.replace(matcher, match => {
|
|
42
|
+
matchedBlock = match;
|
|
43
|
+
return '\n';
|
|
44
|
+
});
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
46
|
+
if (matchedBlock) {
|
|
47
|
+
xml = xml.replace(/<\/inputs>(\r|\n)/, '</inputs>' + matchedBlock);
|
|
48
48
|
}
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
if (xml.includes('/data/init/custom_place_name')) {
|
|
52
|
+
let matchedBlock;
|
|
53
|
+
xml = xml.replace(/\s*<input ref="\/data\/init\/custom_place_name">[^]*?<\/input>/, match => {
|
|
54
|
+
matchedBlock = match;
|
|
55
|
+
return '';
|
|
56
|
+
});
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
58
|
+
if (matchedBlock) {
|
|
59
|
+
const targetMatcher = new RegExp(`\\s*<input ref="/data/${type}/external_id">\\s*(\\r|\\n)`);
|
|
60
|
+
xml = xml.replace(targetMatcher, match => matchedBlock + match);
|
|
61
61
|
}
|
|
62
|
+
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
if (xml.includes('ref="/data/contact"')) {
|
|
65
|
+
const groupRegex = name => new RegExp(`(\\s*)<group(\\s.*)?\\sref="${name}"(\\s.*)?>[^]*?</group>`);
|
|
66
|
+
let matchedBlock;
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
if (xml.match(groupRegex('/data/init'))) {
|
|
69
|
+
xml = xml.replace(groupRegex('/data/contact'), match => {
|
|
70
|
+
matchedBlock = match;
|
|
71
|
+
return '';
|
|
72
|
+
});
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
74
|
+
if (matchedBlock) {
|
|
75
|
+
const stripTrailingGroup = s => s.replace(/[\r\n\s]*<\/group>$/, '');
|
|
76
|
+
xml = xml.replace(groupRegex('/data/init'), match => {
|
|
77
|
+
return stripTrailingGroup(match) +
|
|
78
|
+
stripTrailingGroup(matchedBlock).replace(/\n/g, '\n ') +
|
|
79
|
+
'\n </group>\n </group>';
|
|
80
|
+
});
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
return xml;
|
|
86
|
+
},
|
|
87
|
+
});
|
|
87
88
|
};
|
|
88
89
|
|
|
89
90
|
module.exports = {
|
|
90
91
|
requiresInstance: false,
|
|
91
|
-
|
|
92
|
+
convertContactForm,
|
|
93
|
+
CONTACT_FORMS_PATH,
|
|
94
|
+
execute: () => convertContactForm(environment.extraArgs)
|
|
92
95
|
};
|
package/src/fn/create-users.js
CHANGED
|
@@ -4,7 +4,7 @@ const userPrompt = require('../../src/lib/user-prompt');
|
|
|
4
4
|
const api = require('../lib/api');
|
|
5
5
|
const environment = require('../lib/environment');
|
|
6
6
|
const fs = require('../lib/sync-fs');
|
|
7
|
-
const { info, warn
|
|
7
|
+
const { info, warn } = require('../lib/log');
|
|
8
8
|
|
|
9
9
|
const nestPrefixedProperties = (obj, name) => {
|
|
10
10
|
const nested = {};
|
|
@@ -61,7 +61,7 @@ const getUserInfo = async (user) => {
|
|
|
61
61
|
|
|
62
62
|
const execute = async () => {
|
|
63
63
|
const csvPath = `${environment.pathToProject}/users.csv`;
|
|
64
|
-
if(!fs.exists(csvPath)) {
|
|
64
|
+
if (!fs.exists(csvPath)) {
|
|
65
65
|
throw new Error(`User csv file not found at ${csvPath}`);
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -76,11 +76,8 @@ const execute = async () => {
|
|
|
76
76
|
if (warnings.length) {
|
|
77
77
|
warnings.forEach(warning => warn(warning));
|
|
78
78
|
warn('Are you sure you want to continue?');
|
|
79
|
-
if(!userPrompt.keyInYN()) {
|
|
80
|
-
|
|
81
|
-
process.exit(1);
|
|
82
|
-
// stop execution in tests
|
|
83
|
-
return; // eslint-disable-line no-unreachable
|
|
79
|
+
if (!userPrompt.keyInYN()) {
|
|
80
|
+
throw new Error('User aborted execution.');
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
|
package/src/fn/delete-forms.js
CHANGED
|
@@ -2,22 +2,23 @@ const environment = require('../lib/environment');
|
|
|
2
2
|
const { info, warn } = require('../lib/log');
|
|
3
3
|
const pouch = require('../lib/db');
|
|
4
4
|
|
|
5
|
+
const deleteForms = (forms) => {
|
|
6
|
+
if (!forms || !forms.length) {
|
|
7
|
+
warn('No forms specified for deleting.');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const db = pouch();
|
|
11
|
+
return Promise.all(forms.map(formName => {
|
|
12
|
+
const docId = `form:${formName}`;
|
|
13
|
+
return db.get(docId)
|
|
14
|
+
.then(doc => db.remove(doc))
|
|
15
|
+
.then(() => info('Deleted form:', formName))
|
|
16
|
+
.catch(e => warn(`Failed to remove form with doc ID ${docId}`, e));
|
|
17
|
+
}));
|
|
18
|
+
};
|
|
19
|
+
|
|
5
20
|
module.exports = {
|
|
6
21
|
requiresInstance: true,
|
|
7
|
-
execute: () =>
|
|
8
|
-
|
|
9
|
-
const { extraArgs } = environment;
|
|
10
|
-
if (!extraArgs || !extraArgs.length) {
|
|
11
|
-
warn('No forms specified for deleting.');
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return Promise.all(extraArgs.map(formName => {
|
|
16
|
-
const docId = `form:${formName}`;
|
|
17
|
-
return db.get(docId)
|
|
18
|
-
.then(doc => db.remove(doc))
|
|
19
|
-
.then(() => info('Deleted form:', formName))
|
|
20
|
-
.catch(e => warn(`Failed to remove form with doc ID ${docId}`, e));
|
|
21
|
-
}));
|
|
22
|
-
}
|
|
22
|
+
execute: () => deleteForms(environment.extraArgs),
|
|
23
|
+
deleteForms,
|
|
23
24
|
};
|
package/src/fn/move-contacts.js
CHANGED
|
@@ -7,7 +7,7 @@ const fs = require('../lib/sync-fs');
|
|
|
7
7
|
const lineageManipulation = require('../lib/lineage-manipulation');
|
|
8
8
|
const lineageConstraints = require('../lib/lineage-constraints');
|
|
9
9
|
const pouch = require('../lib/db');
|
|
10
|
-
const { warn, trace, info
|
|
10
|
+
const { warn, trace, info } = require('../lib/log');
|
|
11
11
|
|
|
12
12
|
const HIERARCHY_ROOT = 'root';
|
|
13
13
|
const BATCH_SIZE = 10000;
|
|
@@ -125,8 +125,7 @@ const prepareDocumentDirectory = ({ docDirectoryPath, force }) => {
|
|
|
125
125
|
if(userPrompt.keyInYN()) {
|
|
126
126
|
fs.deleteFilesInFolder(docDirectoryPath);
|
|
127
127
|
} else {
|
|
128
|
-
|
|
129
|
-
process.exit(1);
|
|
128
|
+
throw new Error('User aborted execution.');
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
};
|