domma-cms 0.30.0 → 0.31.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/admin/js/templates/effects.html +752 -752
- package/admin/js/templates/forms.html +17 -17
- package/admin/js/templates/my-profile.html +17 -17
- package/admin/js/templates/role-editor.html +70 -70
- package/admin/js/templates/roles.html +10 -10
- package/bin/lib/config-merge.js +44 -44
- package/package.json +1 -1
- package/server/middleware/auth.js +253 -253
- package/server/routes/api/auth.js +309 -309
- package/server/routes/api/navigation.js +42 -42
- package/server/routes/api/settings.js +141 -141
- package/server/routes/docs-public.js +43 -0
- package/server/routes/public.js +2 -2
- package/server/server.js +10 -0
- package/{scripts/migrate-docs.js → server/services/docs.js} +204 -126
- package/server/services/email.js +167 -167
- package/server/services/userProfiles.js +199 -199
- package/server/services/users.js +302 -302
- package/config/connections.json.bak +0 -9
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<div class="view-header">
|
|
2
|
-
<h1><span data-icon="layout"></span> Forms</h1>
|
|
3
|
-
<div style="display:flex;gap:.5rem;">
|
|
4
|
-
<button id="test-email-btn" class="btn btn-ghost btn-sm">
|
|
5
|
-
<span data-icon="mail"></span> Test Email
|
|
6
|
-
</button>
|
|
7
|
-
<button id="create-form-btn" class="btn btn-primary">
|
|
8
|
-
<span data-icon="plus"></span> Create Form
|
|
9
|
-
</button>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<div class="card">
|
|
14
|
-
<div class="card-body">
|
|
15
|
-
<div id="forms-table"></div>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h1><span data-icon="layout"></span> Forms</h1>
|
|
3
|
+
<div style="display:flex;gap:.5rem;">
|
|
4
|
+
<button id="test-email-btn" class="btn btn-ghost btn-sm">
|
|
5
|
+
<span data-icon="mail"></span> Test Email
|
|
6
|
+
</button>
|
|
7
|
+
<button id="create-form-btn" class="btn btn-primary">
|
|
8
|
+
<span data-icon="plus"></span> Create Form
|
|
9
|
+
</button>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="card">
|
|
14
|
+
<div class="card-body">
|
|
15
|
+
<div id="forms-table"></div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<div class="view-header">
|
|
2
|
-
<h1><span data-icon="user"></span> My Profile</h1>
|
|
3
|
-
</div>
|
|
4
|
-
|
|
5
|
-
<div class="card">
|
|
6
|
-
<div class="card-header"><h2>Account</h2></div>
|
|
7
|
-
<div class="card-body">
|
|
8
|
-
<div id="account-form-container"></div>
|
|
9
|
-
</div>
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<div class="card mt-4" id="profile-card" style="display:none;">
|
|
13
|
-
<div class="card-header"><h2>Profile</h2></div>
|
|
14
|
-
<div class="card-body">
|
|
15
|
-
<div id="profile-form-container"></div>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h1><span data-icon="user"></span> My Profile</h1>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div class="card">
|
|
6
|
+
<div class="card-header"><h2>Account</h2></div>
|
|
7
|
+
<div class="card-body">
|
|
8
|
+
<div id="account-form-container"></div>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="card mt-4" id="profile-card" style="display:none;">
|
|
13
|
+
<div class="card-header"><h2>Profile</h2></div>
|
|
14
|
+
<div class="card-body">
|
|
15
|
+
<div id="profile-form-container"></div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
<div class="view-header">
|
|
2
|
-
<h1><span data-icon="shield"></span> <span id="role-title">Edit Role</span></h1>
|
|
3
|
-
<div>
|
|
4
|
-
<a href="#/roles" class="btn btn-secondary"><span data-icon="arrow-left"></span> Back</a>
|
|
5
|
-
<button id="btn-save-role" class="btn btn-primary"><span data-icon="save"></span> Save</button>
|
|
6
|
-
</div>
|
|
7
|
-
</div>
|
|
8
|
-
|
|
9
|
-
<div class="tabs" id="role-tabs">
|
|
10
|
-
<div class="tab-list">
|
|
11
|
-
<button class="tab-item active">General</button>
|
|
12
|
-
<button class="tab-item">Permissions</button>
|
|
13
|
-
</div>
|
|
14
|
-
<div class="tab-content">
|
|
15
|
-
<!-- General Tab -->
|
|
16
|
-
<div class="tab-panel active" id="panel-general">
|
|
17
|
-
<div class="card">
|
|
18
|
-
<div class="card-body">
|
|
19
|
-
<div class="row">
|
|
20
|
-
<div class="col-6">
|
|
21
|
-
<div class="mb-3">
|
|
22
|
-
<label class="form-label">Name (slug)</label>
|
|
23
|
-
<input id="role-name" type="text" class="form-input" placeholder="e.g. moderator">
|
|
24
|
-
<p class="form-hint">Lowercase identifier. Cannot be changed for the root admin
|
|
25
|
-
role.</p>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
<div class="col-6">
|
|
29
|
-
<div class="mb-3">
|
|
30
|
-
<label class="form-label">Display Label</label>
|
|
31
|
-
<input id="role-label" type="text" class="form-input" placeholder="e.g. Moderator">
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="row">
|
|
36
|
-
<div class="col-6">
|
|
37
|
-
<div class="mb-3">
|
|
38
|
-
<label class="form-label">Level</label>
|
|
39
|
-
<input id="role-level" type="number" class="form-input" min="0">
|
|
40
|
-
<p class="form-hint">Lower = more privileged. 0 is reserved for the root admin.</p>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
<div class="col-6">
|
|
44
|
-
<div class="mb-3">
|
|
45
|
-
<label class="form-label">Badge Colour</label>
|
|
46
|
-
<select id="role-badge" class="form-input"></select>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="row">
|
|
51
|
-
<div class="col-6">
|
|
52
|
-
<div class="mb-3">
|
|
53
|
-
<label class="form-label">Project</label>
|
|
54
|
-
<select id="role-project" class="form-input">
|
|
55
|
-
<option value="">— none —</option>
|
|
56
|
-
</select>
|
|
57
|
-
<p class="form-hint">Tag this role to a project for grouping.</p>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<!-- Permissions Tab -->
|
|
66
|
-
<div class="tab-panel" id="panel-permissions">
|
|
67
|
-
<div id="permissions-container"></div>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h1><span data-icon="shield"></span> <span id="role-title">Edit Role</span></h1>
|
|
3
|
+
<div>
|
|
4
|
+
<a href="#/roles" class="btn btn-secondary"><span data-icon="arrow-left"></span> Back</a>
|
|
5
|
+
<button id="btn-save-role" class="btn btn-primary"><span data-icon="save"></span> Save</button>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="tabs" id="role-tabs">
|
|
10
|
+
<div class="tab-list">
|
|
11
|
+
<button class="tab-item active">General</button>
|
|
12
|
+
<button class="tab-item">Permissions</button>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="tab-content">
|
|
15
|
+
<!-- General Tab -->
|
|
16
|
+
<div class="tab-panel active" id="panel-general">
|
|
17
|
+
<div class="card">
|
|
18
|
+
<div class="card-body">
|
|
19
|
+
<div class="row">
|
|
20
|
+
<div class="col-6">
|
|
21
|
+
<div class="mb-3">
|
|
22
|
+
<label class="form-label">Name (slug)</label>
|
|
23
|
+
<input id="role-name" type="text" class="form-input" placeholder="e.g. moderator">
|
|
24
|
+
<p class="form-hint">Lowercase identifier. Cannot be changed for the root admin
|
|
25
|
+
role.</p>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="col-6">
|
|
29
|
+
<div class="mb-3">
|
|
30
|
+
<label class="form-label">Display Label</label>
|
|
31
|
+
<input id="role-label" type="text" class="form-input" placeholder="e.g. Moderator">
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="row">
|
|
36
|
+
<div class="col-6">
|
|
37
|
+
<div class="mb-3">
|
|
38
|
+
<label class="form-label">Level</label>
|
|
39
|
+
<input id="role-level" type="number" class="form-input" min="0">
|
|
40
|
+
<p class="form-hint">Lower = more privileged. 0 is reserved for the root admin.</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="col-6">
|
|
44
|
+
<div class="mb-3">
|
|
45
|
+
<label class="form-label">Badge Colour</label>
|
|
46
|
+
<select id="role-badge" class="form-input"></select>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="row">
|
|
51
|
+
<div class="col-6">
|
|
52
|
+
<div class="mb-3">
|
|
53
|
+
<label class="form-label">Project</label>
|
|
54
|
+
<select id="role-project" class="form-input">
|
|
55
|
+
<option value="">— none —</option>
|
|
56
|
+
</select>
|
|
57
|
+
<p class="form-hint">Tag this role to a project for grouping.</p>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<!-- Permissions Tab -->
|
|
66
|
+
<div class="tab-panel" id="panel-permissions">
|
|
67
|
+
<div id="permissions-container"></div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
<div class="view-header">
|
|
2
|
-
<h1><span data-icon="shield"></span> Roles & Permissions</h1>
|
|
3
|
-
<button id="btn-add-role" class="btn btn-primary"><span data-icon="plus"></span> Add Role</button>
|
|
4
|
-
</div>
|
|
5
|
-
|
|
6
|
-
<div class="card">
|
|
7
|
-
<div class="card-body">
|
|
8
|
-
<div id="roles-table"></div>
|
|
9
|
-
</div>
|
|
10
|
-
</div>
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h1><span data-icon="shield"></span> Roles & Permissions</h1>
|
|
3
|
+
<button id="btn-add-role" class="btn btn-primary"><span data-icon="plus"></span> Add Role</button>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="card">
|
|
7
|
+
<div class="card-body">
|
|
8
|
+
<div id="roles-table"></div>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
package/bin/lib/config-merge.js
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Domma CMS — Config Merge Utility
|
|
3
|
-
* Merges new keys from an upstream config into an existing user config,
|
|
4
|
-
* without ever overwriting values the user already has.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Deep-merge new keys from `upstream` into `existing`.
|
|
9
|
-
* Existing values are never modified — only missing keys are added.
|
|
10
|
-
*
|
|
11
|
-
* @param {object} existing - The user's current config object
|
|
12
|
-
* @param {object} upstream - The upstream (new version) config object
|
|
13
|
-
* @param {string} [_prefix] - Internal: key path prefix for reporting
|
|
14
|
-
* @returns {{ merged: object, added: string[] }} Merged object + list of added key paths
|
|
15
|
-
*/
|
|
16
|
-
export function deepMergeNewKeys(existing, upstream, _prefix = '') {
|
|
17
|
-
const merged = {...existing};
|
|
18
|
-
const added = [];
|
|
19
|
-
|
|
20
|
-
for (const [key, upstreamVal] of Object.entries(upstream)) {
|
|
21
|
-
const fullKey = _prefix ? `${_prefix}.${key}` : key;
|
|
22
|
-
|
|
23
|
-
if (!(key in existing)) {
|
|
24
|
-
// Key is entirely missing — add it wholesale
|
|
25
|
-
merged[key] = upstreamVal;
|
|
26
|
-
added.push(fullKey);
|
|
27
|
-
} else if (
|
|
28
|
-
upstreamVal !== null &&
|
|
29
|
-
typeof upstreamVal === 'object' &&
|
|
30
|
-
!Array.isArray(upstreamVal) &&
|
|
31
|
-
typeof existing[key] === 'object' &&
|
|
32
|
-
existing[key] !== null &&
|
|
33
|
-
!Array.isArray(existing[key])
|
|
34
|
-
) {
|
|
35
|
-
// Both sides are plain objects — recurse
|
|
36
|
-
const child = deepMergeNewKeys(existing[key], upstreamVal, fullKey);
|
|
37
|
-
merged[key] = child.merged;
|
|
38
|
-
added.push(...child.added);
|
|
39
|
-
}
|
|
40
|
-
// Otherwise: existing value wins — no action
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return {merged, added};
|
|
44
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Domma CMS — Config Merge Utility
|
|
3
|
+
* Merges new keys from an upstream config into an existing user config,
|
|
4
|
+
* without ever overwriting values the user already has.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Deep-merge new keys from `upstream` into `existing`.
|
|
9
|
+
* Existing values are never modified — only missing keys are added.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} existing - The user's current config object
|
|
12
|
+
* @param {object} upstream - The upstream (new version) config object
|
|
13
|
+
* @param {string} [_prefix] - Internal: key path prefix for reporting
|
|
14
|
+
* @returns {{ merged: object, added: string[] }} Merged object + list of added key paths
|
|
15
|
+
*/
|
|
16
|
+
export function deepMergeNewKeys(existing, upstream, _prefix = '') {
|
|
17
|
+
const merged = {...existing};
|
|
18
|
+
const added = [];
|
|
19
|
+
|
|
20
|
+
for (const [key, upstreamVal] of Object.entries(upstream)) {
|
|
21
|
+
const fullKey = _prefix ? `${_prefix}.${key}` : key;
|
|
22
|
+
|
|
23
|
+
if (!(key in existing)) {
|
|
24
|
+
// Key is entirely missing — add it wholesale
|
|
25
|
+
merged[key] = upstreamVal;
|
|
26
|
+
added.push(fullKey);
|
|
27
|
+
} else if (
|
|
28
|
+
upstreamVal !== null &&
|
|
29
|
+
typeof upstreamVal === 'object' &&
|
|
30
|
+
!Array.isArray(upstreamVal) &&
|
|
31
|
+
typeof existing[key] === 'object' &&
|
|
32
|
+
existing[key] !== null &&
|
|
33
|
+
!Array.isArray(existing[key])
|
|
34
|
+
) {
|
|
35
|
+
// Both sides are plain objects — recurse
|
|
36
|
+
const child = deepMergeNewKeys(existing[key], upstreamVal, fullKey);
|
|
37
|
+
merged[key] = child.merged;
|
|
38
|
+
added.push(...child.added);
|
|
39
|
+
}
|
|
40
|
+
// Otherwise: existing value wins — no action
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {merged, added};
|
|
44
|
+
}
|