domma-cms 0.10.0 → 0.13.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/CLAUDE.md +248 -159
- package/admin/css/admin.css +1 -1
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +7 -3
- package/admin/js/config/sidebar-config.js +1 -1
- package/admin/js/http-interceptor.js +1 -0
- package/admin/js/lib/safe-html.js +1 -0
- package/admin/js/templates/documentation.html +611 -2
- package/admin/js/templates/layouts.html +5 -4
- package/admin/js/templates/notifications.html +14 -0
- package/admin/js/templates/plugin-marketplace.html +16 -0
- package/admin/js/templates/plugins.html +17 -5
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/layouts.js +1 -16
- package/admin/js/views/notifications.js +1 -0
- package/admin/js/views/plugin-marketplace.js +1 -0
- package/admin/js/views/plugins.js +16 -16
- package/config/navigation.json +5 -72
- package/config/plugins.json +10 -14
- package/config/presets.json +50 -13
- package/config/site.json +11 -63
- package/package.json +2 -1
- package/plugins/_template/admin/templates/index.html +17 -0
- package/plugins/_template/admin/views/index.js +19 -0
- package/plugins/_template/config.js +8 -0
- package/plugins/_template/plugin.js +23 -0
- package/plugins/_template/plugin.json +34 -0
- package/plugins/analytics/plugin.json +41 -31
- package/plugins/blog/admin/templates/blog.html +22 -0
- package/plugins/blog/admin/templates/categories.html +7 -0
- package/plugins/blog/admin/templates/comments.html +11 -0
- package/plugins/blog/admin/templates/post-editor.html +97 -0
- package/plugins/blog/admin/templates/settings.html +11 -0
- package/plugins/blog/admin/views/blog.js +183 -0
- package/plugins/blog/admin/views/categories.js +235 -0
- package/plugins/blog/admin/views/comments.js +187 -0
- package/plugins/blog/admin/views/post-editor.js +291 -0
- package/plugins/blog/admin/views/settings.js +100 -0
- package/plugins/blog/collections/categories/schema.json +12 -0
- package/plugins/blog/collections/comments/schema.json +16 -0
- package/plugins/blog/collections/posts/schema.json +19 -0
- package/plugins/blog/config.js +8 -0
- package/plugins/blog/plugin.js +352 -0
- package/plugins/blog/plugin.json +96 -0
- package/plugins/blog/roles/blog-author.json +10 -0
- package/plugins/blog/roles/blog-editor.json +12 -0
- package/plugins/blog/templates/author.html +9 -0
- package/plugins/blog/templates/category.html +9 -0
- package/plugins/blog/templates/index.html +9 -0
- package/plugins/blog/templates/post.html +17 -0
- package/plugins/blog/templates/tag.html +9 -0
- package/plugins/contacts/collections/user-contact-groups/schema.json +1 -1
- package/plugins/contacts/collections/user-contacts/schema.json +1 -1
- package/plugins/contacts/plugin.js +4 -10
- package/plugins/contacts/plugin.json +13 -3
- package/plugins/notes/collections/user-notes/schema.json +1 -1
- package/plugins/notes/plugin.js +3 -9
- package/plugins/notes/plugin.json +13 -3
- package/plugins/site-search/plugin.json +5 -2
- package/plugins/theme-switcher/plugin.json +1 -1
- package/plugins/todo/collections/todos/schema.json +1 -1
- package/plugins/todo/plugin.js +3 -9
- package/plugins/todo/plugin.json +13 -3
- package/public/css/site.css +1 -1
- package/scripts/build.js +48 -0
- package/scripts/create-plugin.js +113 -0
- package/scripts/fresh.js +6 -7
- package/scripts/gen-instance-secret.js +46 -0
- package/scripts/reset.js +3 -3
- package/scripts/setup.js +31 -13
- package/server/middleware/auth.js +48 -0
- package/server/middleware/managerAuth.js +36 -0
- package/server/routes/api/actions.js +1 -1
- package/server/routes/api/auth.js +4 -3
- package/server/routes/api/layouts.js +173 -49
- package/server/routes/api/notifications.js +155 -0
- package/server/routes/api/plugin-marketplace.js +75 -0
- package/server/routes/api/users.js +1 -1
- package/server/routes/api/views.js +1 -1
- package/server/routes/public.js +4 -9
- package/server/server.js +32 -3
- package/server/services/actions.js +1 -1
- package/server/services/managerClient.js +182 -0
- package/server/services/markdown.js +52 -14
- package/server/services/permissionRegistry.js +245 -173
- package/server/services/pluginInstaller.js +301 -0
- package/server/services/plugins.js +117 -10
- package/server/services/presetCollections.js +66 -251
- package/server/services/renderer.js +99 -0
- package/server/services/roles.js +191 -39
- package/server/services/users.js +1 -1
- package/server/services/views.js +1 -1
- package/server/templates/page.html +2 -2
- package/plugins/docs/admin/templates/docs.html +0 -69
- package/plugins/docs/admin/views/docs.js +0 -276
- package/plugins/docs/config.js +0 -8
- package/plugins/docs/data/documents/57e003f0-68f2-47dc-9c36-ed4b10ed3deb.json +0 -11
- package/plugins/docs/data/folders.json +0 -9
- package/plugins/docs/data/templates.json +0 -1
- package/plugins/docs/data/versions/57e003f0-68f2-47dc-9c36-ed4b10ed3deb/1.json +0 -5
- package/plugins/docs/plugin.js +0 -375
- package/plugins/docs/plugin.json +0 -23
- package/plugins/form-builder/data/forms/contacts.json +0 -66
- package/plugins/form-builder/data/forms/enquiries.json +0 -103
- package/plugins/form-builder/data/forms/feedback.json +0 -131
- package/plugins/form-builder/data/forms/notes.json +0 -79
- package/plugins/form-builder/data/forms/to-do.json +0 -100
- package/plugins/form-builder/data/submissions/contacts.json +0 -1
- package/plugins/form-builder/data/submissions/enquiries.json +0 -1
- package/plugins/form-builder/data/submissions/feedback.json +0 -1
- package/plugins/form-builder/data/submissions/notes.json +0 -1
- package/plugins/form-builder/data/submissions/to-do.json +0 -1
- package/plugins/garage/admin/templates/garage.html +0 -111
- package/plugins/garage/admin/views/garage.js +0 -622
- package/plugins/garage/collections/garage-vehicles/schema.json +0 -101
- package/plugins/garage/config.js +0 -18
- package/plugins/garage/data/vehicles.json +0 -70
- package/plugins/garage/plugin.js +0 -398
- package/plugins/garage/plugin.json +0 -33
- package/scripts/seed.js +0 -1996
- package/server/services/userTypes.js +0 -227
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Types Service
|
|
3
|
-
* Preset Collection — seeds roles on first startup, caches them in memory.
|
|
4
|
-
* Auth middleware calls getRoleMap() / getPermissionsFor() at request time.
|
|
5
|
-
*/
|
|
6
|
-
import fs from 'fs/promises';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import {v4 as uuidv4} from 'uuid';
|
|
9
|
-
import {config} from '../config.js';
|
|
10
|
-
|
|
11
|
-
const COLLECTIONS_DIR = path.resolve(config.content.collectionsDir);
|
|
12
|
-
const SLUG = 'user-types';
|
|
13
|
-
const DIR = path.join(COLLECTIONS_DIR, SLUG);
|
|
14
|
-
const SCHEMA_PATH = path.join(DIR, 'schema.json');
|
|
15
|
-
const DATA_PATH = path.join(DIR, 'data.json');
|
|
16
|
-
|
|
17
|
-
export const RESOURCES = ['pages', 'settings', 'navigation', 'layouts', 'media', 'users', 'plugins', 'collections', 'views', 'actions', 'blocks'];
|
|
18
|
-
export const ACTIONS = ['read', 'create', 'update', 'delete'];
|
|
19
|
-
|
|
20
|
-
const PRESET_SCHEMA = {
|
|
21
|
-
slug: SLUG,
|
|
22
|
-
title: 'User Types',
|
|
23
|
-
description: 'CMS role definitions — managed by the system.',
|
|
24
|
-
preset: true,
|
|
25
|
-
fields: [
|
|
26
|
-
{name: 'name', label: 'Name (slug)', type: 'text', required: true},
|
|
27
|
-
{name: 'label', label: 'Label', type: 'text', required: true},
|
|
28
|
-
{name: 'level', label: 'Level', type: 'number', required: true},
|
|
29
|
-
{
|
|
30
|
-
name: 'permissions',
|
|
31
|
-
label: 'Permissions',
|
|
32
|
-
type: 'multi-select',
|
|
33
|
-
options: RESOURCES.flatMap(r => [r, ...ACTIONS.map(a => `${r}.${a}`)])
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: 'badgeClass', label: 'Badge Class', type: 'select',
|
|
37
|
-
options: ['badge-danger', 'badge-warning', 'badge-info', 'badge-secondary', 'badge-success', 'badge-primary']
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
|
-
api: {
|
|
41
|
-
create: {enabled: false, access: 'admin'},
|
|
42
|
-
read: {enabled: false, access: 'admin'},
|
|
43
|
-
update: {enabled: false, access: 'admin'},
|
|
44
|
-
delete: {enabled: false, access: 'admin'}
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const SEED_ENTRIES = [
|
|
49
|
-
{name: 'admin', label: 'Admin', level: 0, permissions: RESOURCES, badgeClass: 'badge-danger'},
|
|
50
|
-
{
|
|
51
|
-
name: 'manager',
|
|
52
|
-
label: 'Manager',
|
|
53
|
-
level: 1,
|
|
54
|
-
permissions: ['pages', 'settings', 'navigation', 'layouts', 'media', 'users', 'collections', 'views', 'actions'],
|
|
55
|
-
badgeClass: 'badge-warning'
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'editor',
|
|
59
|
-
label: 'Editor',
|
|
60
|
-
level: 2,
|
|
61
|
-
permissions: ['pages.read', 'pages.create', 'pages.update', 'media'],
|
|
62
|
-
badgeClass: 'badge-info'
|
|
63
|
-
},
|
|
64
|
-
{name: 'subscriber', label: 'Subscriber', level: 3, permissions: [], badgeClass: 'badge-secondary'}
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// In-memory cache
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
|
|
71
|
-
/** @type {Map<string,{label:string,level:number,badgeClass:string}>} */
|
|
72
|
-
let roleMap = new Map();
|
|
73
|
-
|
|
74
|
-
/** @type {Map<string,string[]>} resource (and resource.action) → role names */
|
|
75
|
-
let permissionsMap = new Map();
|
|
76
|
-
|
|
77
|
-
/** @type {Map<string,string[]>} role name → raw permissions array */
|
|
78
|
-
let rawPermissionsMap = new Map();
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Build in-memory maps from an array of data entries.
|
|
82
|
-
* Supports both bare resource names ('pages') and dotted action strings ('pages.read').
|
|
83
|
-
* Bare names expand to all four actions for backward compatibility.
|
|
84
|
-
*
|
|
85
|
-
* @param {object[]} entries
|
|
86
|
-
*/
|
|
87
|
-
function buildCache(entries) {
|
|
88
|
-
roleMap = new Map();
|
|
89
|
-
permissionsMap = new Map();
|
|
90
|
-
rawPermissionsMap = new Map();
|
|
91
|
-
|
|
92
|
-
const addTo = (key, role) => {
|
|
93
|
-
if (!permissionsMap.has(key)) permissionsMap.set(key, []);
|
|
94
|
-
if (!permissionsMap.get(key).includes(role)) permissionsMap.get(key).push(role);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
for (const entry of entries) {
|
|
98
|
-
const d = entry.data;
|
|
99
|
-
roleMap.set(d.name, {label: d.label, level: d.level, badgeClass: d.badgeClass || ''});
|
|
100
|
-
rawPermissionsMap.set(d.name, d.permissions || []);
|
|
101
|
-
for (const perm of (d.permissions || [])) {
|
|
102
|
-
if (perm.includes('.')) {
|
|
103
|
-
const [res] = perm.split('.');
|
|
104
|
-
addTo(perm, d.name); // 'pages.read' → [role]
|
|
105
|
-
addTo(res, d.name); // 'pages' → [role] (any-action union)
|
|
106
|
-
} else {
|
|
107
|
-
addTo(perm, d.name); // 'pages' (bare) → [role]
|
|
108
|
-
for (const action of ACTIONS) {
|
|
109
|
-
addTo(`${perm}.${action}`, d.name); // expand to all actions
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
// Public API
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Seed the preset collection on first startup (no-op if data.json already exists).
|
|
122
|
-
*
|
|
123
|
-
* @returns {Promise<void>}
|
|
124
|
-
*/
|
|
125
|
-
export async function seed() {
|
|
126
|
-
await fs.mkdir(DIR, {recursive: true});
|
|
127
|
-
|
|
128
|
-
// Always write schema (overwrite to keep in sync with code)
|
|
129
|
-
await fs.writeFile(SCHEMA_PATH, JSON.stringify(PRESET_SCHEMA, null, 2) + '\n', 'utf8');
|
|
130
|
-
|
|
131
|
-
// Only write data if it doesn't exist yet
|
|
132
|
-
try {
|
|
133
|
-
await fs.access(DATA_PATH);
|
|
134
|
-
} catch {
|
|
135
|
-
const entries = SEED_ENTRIES.map(data => ({
|
|
136
|
-
id: uuidv4(),
|
|
137
|
-
data,
|
|
138
|
-
createdAt: new Date().toISOString(),
|
|
139
|
-
updatedAt: new Date().toISOString()
|
|
140
|
-
}));
|
|
141
|
-
await fs.writeFile(DATA_PATH, JSON.stringify(entries, null, 2) + '\n', 'utf8');
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Load the collection from disk into the in-memory cache.
|
|
147
|
-
*
|
|
148
|
-
* @returns {Promise<void>}
|
|
149
|
-
*/
|
|
150
|
-
export async function load() {
|
|
151
|
-
try {
|
|
152
|
-
const raw = await fs.readFile(DATA_PATH, 'utf8');
|
|
153
|
-
const entries = JSON.parse(raw);
|
|
154
|
-
buildCache(entries);
|
|
155
|
-
} catch (err) {
|
|
156
|
-
console.warn('[userTypes] Failed to load user-types collection:', err.message);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Reload from disk — call after any CRUD on the user-types collection.
|
|
162
|
-
*
|
|
163
|
-
* @returns {Promise<void>}
|
|
164
|
-
*/
|
|
165
|
-
export async function invalidate() {
|
|
166
|
-
await load();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Return the full role map.
|
|
171
|
-
*
|
|
172
|
-
* @returns {Map<string,{label:string,level:number,badgeClass:string}>}
|
|
173
|
-
*/
|
|
174
|
-
export function getRoleMap() {
|
|
175
|
-
return roleMap;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Return the level for a named role, or Infinity if not found.
|
|
180
|
-
*
|
|
181
|
-
* @param {string} roleName
|
|
182
|
-
* @returns {number}
|
|
183
|
-
*/
|
|
184
|
-
export function getRoleLevel(roleName) {
|
|
185
|
-
return roleMap.get(roleName)?.level ?? Infinity;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Return the role names allowed to access a resource (and optional action).
|
|
190
|
-
* - getPermissionsFor('pages') → roles with ANY action on pages (backward compat)
|
|
191
|
-
* - getPermissionsFor('pages', 'delete')→ roles with delete on pages
|
|
192
|
-
* - getPermissionsFor('pages.delete') → same as above (dot-notation shorthand)
|
|
193
|
-
*
|
|
194
|
-
* @param {string} resource - Resource key, or 'resource.action' dot notation
|
|
195
|
-
* @param {string} [action] - Optional action (read | create | update | delete)
|
|
196
|
-
* @returns {string[]}
|
|
197
|
-
*/
|
|
198
|
-
export function getPermissionsFor(resource, action) {
|
|
199
|
-
if (action) {
|
|
200
|
-
return permissionsMap.get(`${resource}.${action}`) ?? [];
|
|
201
|
-
}
|
|
202
|
-
if (resource.includes('.')) {
|
|
203
|
-
return permissionsMap.get(resource) ?? [];
|
|
204
|
-
}
|
|
205
|
-
return permissionsMap.get(resource) ?? [];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Return the raw permissions array for a role — used by the /api/auth/permissions endpoint.
|
|
210
|
-
*
|
|
211
|
-
* @param {string} roleName
|
|
212
|
-
* @returns {string[]}
|
|
213
|
-
*/
|
|
214
|
-
export function getPermissionsForRole(roleName) {
|
|
215
|
-
return rawPermissionsMap.get(roleName) ?? [];
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Return role names ordered from most to least privileged.
|
|
220
|
-
*
|
|
221
|
-
* @returns {string[]}
|
|
222
|
-
*/
|
|
223
|
-
export function getRoleHierarchy() {
|
|
224
|
-
return [...roleMap.entries()]
|
|
225
|
-
.sort((a, b) => a[1].level - b[1].level)
|
|
226
|
-
.map(([key]) => key);
|
|
227
|
-
}
|