@intranefr/superbackend 1.6.7 → 1.7.8
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/.beads/.br_history/issues.20260314_212352_900045509.jsonl +0 -0
- package/.beads/.br_history/issues.20260314_212352_900045509.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl +2 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl +3 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl +4 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl +5 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl +6 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl +8 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl.meta.json +1 -0
- package/.beads/config.yaml +4 -0
- package/.beads/issues.jsonl +8 -0
- package/.beads/metadata.json +4 -0
- package/.env.example +8 -0
- package/autochangelog/.env.example +36 -0
- package/autochangelog/README.md +412 -0
- package/autochangelog/config/database.js +27 -0
- package/autochangelog/package.json +47 -0
- package/autochangelog/public/landing.html +581 -0
- package/autochangelog/server.js +104 -0
- package/autochangelog/src/app.js +181 -0
- package/autochangelog/src/config/database.js +26 -0
- package/autochangelog/src/controllers/auth.js +488 -0
- package/autochangelog/src/controllers/changelog.js +682 -0
- package/autochangelog/src/controllers/project.js +580 -0
- package/autochangelog/src/controllers/repository.js +780 -0
- package/autochangelog/src/middleware/auth.js +386 -0
- package/autochangelog/src/models/Changelog.js +443 -0
- package/autochangelog/src/models/Project.js +226 -0
- package/autochangelog/src/models/Repository.js +366 -0
- package/autochangelog/src/models/User.js +223 -0
- package/autochangelog/src/routes/auth.routes.js +32 -0
- package/autochangelog/src/routes/changelog.routes.js +42 -0
- package/autochangelog/src/routes/github-auth.routes.js +102 -0
- package/autochangelog/src/routes/project.routes.js +50 -0
- package/autochangelog/src/routes/repository.routes.js +54 -0
- package/autochangelog/src/services/changelog.js +722 -0
- package/autochangelog/src/services/github.js +243 -0
- package/autochangelog/utils/logger.js +77 -0
- package/autochangelog/views/404.ejs +18 -0
- package/autochangelog/views/dashboard.ejs +596 -0
- package/autochangelog/views/index.ejs +231 -0
- package/autochangelog/views/layouts/main.ejs +44 -0
- package/autochangelog/views/login.ejs +104 -0
- package/autochangelog/views/partials/footer.ejs +20 -0
- package/autochangelog/views/partials/navbar.ejs +51 -0
- package/autochangelog/views/register.ejs +109 -0
- package/autochangelog-cli/README.md +266 -0
- package/autochangelog-cli/bin/autochangelog +120 -0
- package/autochangelog-cli/package.json +46 -0
- package/autochangelog-cli/src/cli/commands/auth.js +291 -0
- package/autochangelog-cli/src/cli/commands/changelog.js +619 -0
- package/autochangelog-cli/src/cli/commands/project.js +427 -0
- package/autochangelog-cli/src/cli/commands/repo.js +557 -0
- package/autochangelog-cli/src/cli/commands/stats.js +706 -0
- package/autochangelog-cli/src/cli/utils/config.js +277 -0
- package/autochangelog-cli/src/cli/utils/errors.js +307 -0
- package/autochangelog-cli/src/cli/utils/logger.js +75 -0
- package/autochangelog-cli/src/cli/utils/output.js +357 -0
- package/package.json +9 -3
- package/plugins/supercli/README.md +108 -0
- package/plugins/supercli/plugin.json +123 -0
- package/server.js +1 -1
- package/src/cli/api.js +380 -0
- package/src/cli/direct/agent-utils.js +61 -0
- package/src/cli/direct/cli-utils.js +112 -0
- package/src/cli/direct/data-seeding.js +307 -0
- package/src/cli/direct/db-admin.js +84 -0
- package/src/cli/direct/db-advanced.js +372 -0
- package/src/cli/direct/db-utils.js +558 -0
- package/src/cli/direct/help.js +195 -0
- package/src/cli/direct/migration.js +107 -0
- package/src/cli/direct/rbac-advanced.js +132 -0
- package/src/cli/direct/resources-additional.js +400 -0
- package/src/cli/direct/resources-cms-advanced.js +173 -0
- package/src/cli/direct/resources-cms.js +247 -0
- package/src/cli/direct/resources-core.js +253 -0
- package/src/cli/direct/resources-execution.js +367 -0
- package/src/cli/direct/resources-health.js +152 -0
- package/src/cli/direct/resources-integrations.js +182 -0
- package/src/cli/direct/resources-logs.js +204 -0
- package/src/cli/direct/resources-org-rbac.js +187 -0
- package/src/cli/direct/resources-system.js +236 -0
- package/src/cli/direct.js +556 -0
- package/src/controllers/admin.controller.js +4 -0
- package/src/controllers/auth.controller.js +148 -1
- package/src/controllers/waitingList.controller.js +130 -1
- package/src/models/RbacRole.js +1 -1
- package/src/models/User.js +39 -5
- package/src/routes/auth.routes.js +6 -0
- package/src/routes/waitingList.routes.js +12 -2
- package/src/routes/waitingListAdmin.routes.js +3 -0
- package/src/services/email.service.js +1 -0
- package/src/services/github.service.js +255 -0
- package/src/services/rateLimiter.service.js +29 -1
- package/src/services/waitingListJson.service.js +32 -3
- package/views/admin-waiting-list.ejs +386 -3
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Help text for the direct CLI
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { colorize } = require('./cli-utils');
|
|
8
|
+
|
|
9
|
+
function printHelp() {
|
|
10
|
+
console.log(`
|
|
11
|
+
${colorize("bold", "SuperBackend Direct CLI")}
|
|
12
|
+
|
|
13
|
+
${colorize("bold", "Usage:")}
|
|
14
|
+
node src/cli/direct.js <resource> <command> [options]
|
|
15
|
+
|
|
16
|
+
${colorize("bold", "Resources & Commands:")}
|
|
17
|
+
|
|
18
|
+
${colorize("cyan", "agents")} - Manage AI agents
|
|
19
|
+
list, get, create, update, delete
|
|
20
|
+
|
|
21
|
+
${colorize("cyan", "settings")} - Manage global settings
|
|
22
|
+
list, get, create, update, delete
|
|
23
|
+
|
|
24
|
+
${colorize("cyan", "users")} - Manage users
|
|
25
|
+
list, get, create, update, delete, disable, enable
|
|
26
|
+
|
|
27
|
+
${colorize("cyan", "json-configs")} - Manage JSON configs
|
|
28
|
+
list, get, create, update, delete
|
|
29
|
+
|
|
30
|
+
${colorize("cyan", "blog-posts")} - Manage blog posts
|
|
31
|
+
list, get, create, update, delete, publish, unpublish
|
|
32
|
+
|
|
33
|
+
${colorize("cyan", "orgs")} - Manage organizations
|
|
34
|
+
list, get, create, update, delete
|
|
35
|
+
|
|
36
|
+
${colorize("cyan", "crons")} - Manage cron jobs
|
|
37
|
+
list, get, create, delete, enable, disable
|
|
38
|
+
|
|
39
|
+
${colorize("cyan", "errors")} - Manage error logs
|
|
40
|
+
list, get, delete, clear
|
|
41
|
+
|
|
42
|
+
${colorize("cyan", "scripts")} - Manage script definitions
|
|
43
|
+
list, get, create, delete
|
|
44
|
+
|
|
45
|
+
${colorize("cyan", "workflows")} - Manage workflows
|
|
46
|
+
list, get, create, delete, enable, disable
|
|
47
|
+
|
|
48
|
+
${colorize("cyan", "health-checks")} - Manage health checks
|
|
49
|
+
list, get, create, delete
|
|
50
|
+
|
|
51
|
+
${colorize("cyan", "pages")} - Manage pages
|
|
52
|
+
list, get, create, update, delete
|
|
53
|
+
|
|
54
|
+
${colorize("cyan", "assets")} - Manage assets
|
|
55
|
+
list, get, delete, clear
|
|
56
|
+
|
|
57
|
+
${colorize("cyan", "forms")} - Manage form submissions
|
|
58
|
+
list, get, delete, clear
|
|
59
|
+
|
|
60
|
+
${colorize("cyan", "i18n")} - Manage i18n entries
|
|
61
|
+
list, get, create, delete
|
|
62
|
+
|
|
63
|
+
${colorize("cyan", "notifications")} - Manage notifications
|
|
64
|
+
list, get, delete, clear
|
|
65
|
+
|
|
66
|
+
${colorize("cyan", "rbac-roles")} - Manage RBAC roles
|
|
67
|
+
list, get, create, delete
|
|
68
|
+
|
|
69
|
+
${colorize("cyan", "rbac-groups")} - Manage RBAC groups
|
|
70
|
+
list, get, create, delete
|
|
71
|
+
|
|
72
|
+
${colorize("cyan", "invites")} - Manage invites
|
|
73
|
+
list, get, create, delete, clear
|
|
74
|
+
|
|
75
|
+
${colorize("cyan", "waiting-list")} - Manage waiting list
|
|
76
|
+
list, delete, clear
|
|
77
|
+
|
|
78
|
+
${colorize("cyan", "cache")} - Manage cache entries
|
|
79
|
+
list, get, delete, clear
|
|
80
|
+
|
|
81
|
+
${colorize("cyan", "audit-logs")} - Manage audit logs
|
|
82
|
+
list, get, clear
|
|
83
|
+
|
|
84
|
+
${colorize("cyan", "db-stats")} - Database statistics
|
|
85
|
+
${colorize("cyan", "db-indexes")} - Database indexes
|
|
86
|
+
${colorize("cyan", "db-cleanup")} - Database cleanup
|
|
87
|
+
|
|
88
|
+
${colorize("cyan", "experiments")} - Manage experiments
|
|
89
|
+
${colorize("cyan", "experiment-assignments")} - Experiment assignments
|
|
90
|
+
|
|
91
|
+
${colorize("cyan", "telegram")} - Manage Telegram bots
|
|
92
|
+
${colorize("cyan", "rate-limits")} - Manage rate limits
|
|
93
|
+
${colorize("cyan", "console-logs")} - Manage console logs
|
|
94
|
+
${colorize("cyan", "activity-logs")} - Manage activity logs
|
|
95
|
+
${colorize("cyan", "email-logs")} - Manage email logs
|
|
96
|
+
${colorize("cyan", "webhooks")} - Manage webhooks
|
|
97
|
+
|
|
98
|
+
${colorize("cyan", "stripe-items")} - Stripe catalog items
|
|
99
|
+
${colorize("cyan", "stripe-events")} - Stripe webhook events
|
|
100
|
+
|
|
101
|
+
${colorize("cyan", "demo-projects")} - Demo projects
|
|
102
|
+
${colorize("cyan", "demo-steps")} - Demo steps
|
|
103
|
+
|
|
104
|
+
${colorize("cyan", "external-dbs")} - External DB connections
|
|
105
|
+
${colorize("cyan", "org-members")} - Organization members
|
|
106
|
+
|
|
107
|
+
${colorize("cyan", "page-collections")} - Page collections
|
|
108
|
+
${colorize("cyan", "block-definitions")} - Block definitions
|
|
109
|
+
${colorize("cyan", "context-blocks")} - Context blocks
|
|
110
|
+
${colorize("cyan", "ui-components")} - UI components
|
|
111
|
+
${colorize("cyan", "headless-models")} - Headless models
|
|
112
|
+
${colorize("cyan", "headless-tokens")} - Headless API tokens
|
|
113
|
+
|
|
114
|
+
${colorize("cyan", "blog-automation-locks")} - Blog automation locks
|
|
115
|
+
${colorize("cyan", "blog-automation-runs")} - Blog automation runs
|
|
116
|
+
|
|
117
|
+
${colorize("cyan", "cron-executions")} - Cron execution history
|
|
118
|
+
${colorize("cyan", "workflow-executions")} - Workflow executions
|
|
119
|
+
${colorize("cyan", "script-runs")} - Script execution history
|
|
120
|
+
|
|
121
|
+
${colorize("cyan", "health-incidents")} - Health incidents
|
|
122
|
+
${colorize("cyan", "health-attempts")} - Health auto-heal attempts
|
|
123
|
+
|
|
124
|
+
${colorize("cyan", "error-aggregates")} - Error aggregates
|
|
125
|
+
${colorize("cyan", "metric-buckets")} - Metric buckets
|
|
126
|
+
|
|
127
|
+
${colorize("cyan", "virtual-ejs-files")} - Virtual EJS files
|
|
128
|
+
${colorize("cyan", "virtual-ejs-groups")} - Virtual EJS groups
|
|
129
|
+
${colorize("cyan", "markdowns")} - Manage markdowns
|
|
130
|
+
|
|
131
|
+
${colorize("cyan", "batch-delete")} - Batch delete documents
|
|
132
|
+
${colorize("cyan", "batch-update")} - Batch update documents
|
|
133
|
+
${colorize("cyan", "collection-count")} - Count documents
|
|
134
|
+
${colorize("cyan", "collection-schema")} - Show collection schema
|
|
135
|
+
${colorize("cyan", "export-collection")} - Export collection to JSON
|
|
136
|
+
|
|
137
|
+
${colorize("cyan", "find-duplicates")} - Find duplicate documents
|
|
138
|
+
${colorize("cyan", "remove-duplicates")} - Remove duplicate documents
|
|
139
|
+
${colorize("cyan", "validate-refs")} - Validate references
|
|
140
|
+
${colorize("cyan", "repair-refs")} - Repair broken references
|
|
141
|
+
|
|
142
|
+
${colorize("cyan", "add-index")} - Add index to collection
|
|
143
|
+
${colorize("cyan", "drop-index")} - Drop index from collection
|
|
144
|
+
${colorize("cyan", "reindex")} - Rebuild collection indexes
|
|
145
|
+
${colorize("cyan", "compact")} - Compact collection
|
|
146
|
+
${colorize("cyan", "validate-collection")} - Validate collection integrity
|
|
147
|
+
${colorize("cyan", "rename-collection")} - Rename collection
|
|
148
|
+
${colorize("cyan", "list-collections")} - List all collections
|
|
149
|
+
${colorize("cyan", "create-collection")} - Create new collection
|
|
150
|
+
${colorize("cyan", "drop-collection")} - Drop collection
|
|
151
|
+
|
|
152
|
+
${colorize("cyan", "db-info")} - Database server info
|
|
153
|
+
${colorize("cyan", "db-users")} - Database users
|
|
154
|
+
${colorize("cyan", "slow-queries")} - Find slow queries
|
|
155
|
+
${colorize("cyan", "enable-profiling")} - Enable query profiling
|
|
156
|
+
${colorize("cyan", "disable-profiling")} - Disable query profiling
|
|
157
|
+
|
|
158
|
+
${colorize("cyan", "user-permissions")} - Show user permissions
|
|
159
|
+
${colorize("cyan", "grant-role")} - Grant role to user
|
|
160
|
+
${colorize("cyan", "revoke-role")} - Revoke role from user
|
|
161
|
+
${colorize("cyan", "group-members")} - Show group members
|
|
162
|
+
${colorize("cyan", "add-to-group")} - Add user to group
|
|
163
|
+
${colorize("cyan", "remove-from-group")} - Remove user from group
|
|
164
|
+
|
|
165
|
+
${colorize("cyan", "agent-stats")} - Agent statistics
|
|
166
|
+
${colorize("cyan", "agent-sessions")} - List agent sessions
|
|
167
|
+
${colorize("cyan", "clear-agent-sessions")} - Clear old sessions
|
|
168
|
+
|
|
169
|
+
${colorize("cyan", "migration-status")} - Migration status check
|
|
170
|
+
${colorize("cyan", "add-timestamps")} - Add timestamps to docs
|
|
171
|
+
${colorize("cyan", "data-digest")} - Database digest report
|
|
172
|
+
|
|
173
|
+
${colorize("bold", "Options:")}
|
|
174
|
+
--name NAME Resource name
|
|
175
|
+
--model MODEL AI model name (for agents)
|
|
176
|
+
--key KEY Setting key / Collection name / User ID
|
|
177
|
+
--value VALUE Value (context-dependent)
|
|
178
|
+
--description DESC Description / Additional parameter
|
|
179
|
+
--email EMAIL User email
|
|
180
|
+
--password PASSWORD User password
|
|
181
|
+
--role ROLE User role
|
|
182
|
+
--alias ALIAS JSON config alias
|
|
183
|
+
--json JSON JSON config data
|
|
184
|
+
--output FORMAT Output: json, text, table (default: json)
|
|
185
|
+
--quiet Only output data
|
|
186
|
+
--verbose Show additional details
|
|
187
|
+
-h, --help Show this help
|
|
188
|
+
|
|
189
|
+
${colorize("bold", "Environment Variables:")}
|
|
190
|
+
MONGODB_URI MongoDB connection string
|
|
191
|
+
MODE Environment mode (loads .env.MODE)
|
|
192
|
+
`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
module.exports = { printHelp };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration utilities: migration-status, add-timestamps, data-digest
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const mongoose = require("mongoose");
|
|
8
|
+
|
|
9
|
+
const migrationStatus = {
|
|
10
|
+
async execute(options, context) {
|
|
11
|
+
if (options.command && options.command !== "execute") return;
|
|
12
|
+
const db = context.db;
|
|
13
|
+
const collections = await db.listCollections().toArray();
|
|
14
|
+
const status = {};
|
|
15
|
+
|
|
16
|
+
for (const coll of collections) {
|
|
17
|
+
const count = await db.collection(coll.name).countDocuments();
|
|
18
|
+
const sample = await db.collection(coll.name).findOne();
|
|
19
|
+
status[coll.name] = {
|
|
20
|
+
count,
|
|
21
|
+
hasCreatedAt: sample?.createdAt ? true : false,
|
|
22
|
+
hasUpdatedAt: sample?.updatedAt ? true : false,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return { totalCollections: collections.length, status };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const addTimestamps = {
|
|
31
|
+
async execute(options, context) {
|
|
32
|
+
const db = context.db;
|
|
33
|
+
const collectionName = options.key;
|
|
34
|
+
const dryRun = options.value === "dry";
|
|
35
|
+
|
|
36
|
+
if (!collectionName) throw new Error("--key (collection name) is required");
|
|
37
|
+
|
|
38
|
+
const collection = db.collection(collectionName);
|
|
39
|
+
const docs = await collection
|
|
40
|
+
.find({
|
|
41
|
+
$or: [
|
|
42
|
+
{ createdAt: { $exists: false } },
|
|
43
|
+
{ updatedAt: { $exists: false } },
|
|
44
|
+
],
|
|
45
|
+
})
|
|
46
|
+
.toArray();
|
|
47
|
+
|
|
48
|
+
if (dryRun) {
|
|
49
|
+
return {
|
|
50
|
+
collection: collectionName,
|
|
51
|
+
dryRun: true,
|
|
52
|
+
docsToUpdate: docs.length,
|
|
53
|
+
samples: docs.slice(0, 5).map((d) => ({ _id: d._id })),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let updatedCount = 0;
|
|
58
|
+
const now = new Date();
|
|
59
|
+
|
|
60
|
+
for (const doc of docs) {
|
|
61
|
+
await collection.updateOne(
|
|
62
|
+
{ _id: doc._id },
|
|
63
|
+
{
|
|
64
|
+
$set: {
|
|
65
|
+
createdAt: doc.createdAt || now,
|
|
66
|
+
updatedAt: doc.updatedAt || now,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
updatedCount++;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { collection: collectionName, updatedCount, totalDocs: docs.length };
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const dataDigest = {
|
|
78
|
+
async execute(options, context) {
|
|
79
|
+
if (options.command && options.command !== "execute") return;
|
|
80
|
+
const db = context.db;
|
|
81
|
+
const collections = await db.listCollections().toArray();
|
|
82
|
+
|
|
83
|
+
const digest = {
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
totalCollections: collections.length,
|
|
86
|
+
totalDocuments: 0,
|
|
87
|
+
totalSize: 0,
|
|
88
|
+
collections: [],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
for (const coll of collections) {
|
|
92
|
+
const stats = await db.collection(coll.name).stats();
|
|
93
|
+
digest.totalDocuments += stats.count;
|
|
94
|
+
digest.totalSize += stats.size;
|
|
95
|
+
digest.collections.push({
|
|
96
|
+
name: coll.name,
|
|
97
|
+
count: stats.count,
|
|
98
|
+
size: stats.size,
|
|
99
|
+
storageSize: stats.storageSize,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return digest;
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
module.exports = { migrationStatus, addTimestamps, dataDigest };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* RBAC Advanced: user-permissions, grant-role, revoke-role, group-members, add-to-group, remove-from-group
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const mongoose = require('mongoose');
|
|
8
|
+
|
|
9
|
+
const userPermissions = {
|
|
10
|
+
async execute(options) {
|
|
11
|
+
const User = mongoose.model('User');
|
|
12
|
+
const RbacUserRole = mongoose.model('RbacUserRole');
|
|
13
|
+
const RbacRole = mongoose.model('RbacRole');
|
|
14
|
+
|
|
15
|
+
const userId = options.key;
|
|
16
|
+
if (!userId) throw new Error('--key (user ID) is required');
|
|
17
|
+
|
|
18
|
+
const user = await User.findById(userId).lean();
|
|
19
|
+
if (!user) return { error: 'User not found' };
|
|
20
|
+
|
|
21
|
+
const userRoles = await RbacUserRole.find({ userId }).populate('roleId').lean();
|
|
22
|
+
const roles = userRoles.map(ur => ur.roleId);
|
|
23
|
+
|
|
24
|
+
return { userId, email: user.email, role: user.role, rbacRoles: roles.map(r => ({ name: r.name, description: r.description })) };
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const grantRole = {
|
|
29
|
+
async execute(options) {
|
|
30
|
+
const RbacUserRole = mongoose.model('RbacUserRole');
|
|
31
|
+
const RbacRole = mongoose.model('RbacRole');
|
|
32
|
+
|
|
33
|
+
const userId = options.key;
|
|
34
|
+
const roleName = options.value;
|
|
35
|
+
|
|
36
|
+
if (!userId) throw new Error('--key (user ID) is required');
|
|
37
|
+
if (!roleName) throw new Error('--value (role name) is required');
|
|
38
|
+
|
|
39
|
+
const role = await RbacRole.findOne({ name: roleName });
|
|
40
|
+
if (!role) throw new Error(`Role '${roleName}' not found`);
|
|
41
|
+
|
|
42
|
+
const existing = await RbacUserRole.findOne({ userId, roleId: role._id });
|
|
43
|
+
if (existing) return { message: 'User already has this role', userId, roleId: role._id };
|
|
44
|
+
|
|
45
|
+
await RbacUserRole.create({ userId, roleId: role._id });
|
|
46
|
+
return { success: true, userId, roleId: role._id, roleName };
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const revokeRole = {
|
|
51
|
+
async execute(options) {
|
|
52
|
+
const RbacUserRole = mongoose.model('RbacUserRole');
|
|
53
|
+
const RbacRole = mongoose.model('RbacRole');
|
|
54
|
+
|
|
55
|
+
const userId = options.key;
|
|
56
|
+
const roleName = options.value;
|
|
57
|
+
|
|
58
|
+
if (!userId) throw new Error('--key (user ID) is required');
|
|
59
|
+
if (!roleName) throw new Error('--value (role name) is required');
|
|
60
|
+
|
|
61
|
+
const role = await RbacRole.findOne({ name: roleName });
|
|
62
|
+
if (!role) throw new Error(`Role '${roleName}' not found`);
|
|
63
|
+
|
|
64
|
+
const result = await RbacUserRole.deleteOne({ userId, roleId: role._id });
|
|
65
|
+
return { success: result.deletedCount > 0, userId, roleId: role._id, roleName };
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const groupMembers = {
|
|
70
|
+
async execute(options) {
|
|
71
|
+
const RbacGroup = mongoose.model('RbacGroup');
|
|
72
|
+
const RbacGroupMember = mongoose.model('RbacGroupMember');
|
|
73
|
+
|
|
74
|
+
const groupId = options.key;
|
|
75
|
+
|
|
76
|
+
if (!groupId) {
|
|
77
|
+
const groups = await RbacGroup.find().lean();
|
|
78
|
+
const result = [];
|
|
79
|
+
for (const group of groups) {
|
|
80
|
+
const members = await RbacGroupMember.find({ groupId }).populate('userId').lean();
|
|
81
|
+
result.push({
|
|
82
|
+
groupId: group._id,
|
|
83
|
+
name: group.name,
|
|
84
|
+
memberCount: members.length,
|
|
85
|
+
members: members.map(m => ({ userId: m.userId?._id, email: m.userId?.email })),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return { groups: result };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const group = await RbacGroup.findById(groupId).lean();
|
|
92
|
+
if (!group) throw new Error('Group not found');
|
|
93
|
+
|
|
94
|
+
const members = await RbacGroupMember.find({ groupId }).populate('userId').lean();
|
|
95
|
+
return { groupId, name: group.name, members: members.map(m => ({ userId: m.userId?._id, email: m.userId?.email })) };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const addToGroup = {
|
|
100
|
+
async execute(options) {
|
|
101
|
+
const RbacGroupMember = mongoose.model('RbacGroupMember');
|
|
102
|
+
|
|
103
|
+
const groupId = options.key;
|
|
104
|
+
const userId = options.value;
|
|
105
|
+
|
|
106
|
+
if (!groupId) throw new Error('--key (group ID) is required');
|
|
107
|
+
if (!userId) throw new Error('--value (user ID) is required');
|
|
108
|
+
|
|
109
|
+
const existing = await RbacGroupMember.findOne({ groupId, userId });
|
|
110
|
+
if (existing) return { message: 'User already in group', groupId, userId };
|
|
111
|
+
|
|
112
|
+
await RbacGroupMember.create({ groupId, userId });
|
|
113
|
+
return { success: true, groupId, userId };
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const removeFromGroup = {
|
|
118
|
+
async execute(options) {
|
|
119
|
+
const RbacGroupMember = mongoose.model('RbacGroupMember');
|
|
120
|
+
|
|
121
|
+
const groupId = options.key;
|
|
122
|
+
const userId = options.value;
|
|
123
|
+
|
|
124
|
+
if (!groupId) throw new Error('--key (group ID) is required');
|
|
125
|
+
if (!userId) throw new Error('--value (user ID) is required');
|
|
126
|
+
|
|
127
|
+
const result = await RbacGroupMember.deleteOne({ groupId, userId });
|
|
128
|
+
return { success: result.deletedCount > 0, groupId, userId };
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
module.exports = { userPermissions, grantRole, revokeRole, groupMembers, addToGroup, removeFromGroup };
|