User/Usergroup Pages first draft

This commit is contained in:
root
2025-10-27 19:36:44 +00:00
parent a76567969a
commit d65585b821
12 changed files with 769 additions and 51 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
import { db } from '../db/index.js';
const selectGroupsWithMembers = db.prepare(`
SELECT
g.id,
g.name,
g.description,
g.created_at,
g.updated_at,
COUNT(DISTINCT u.id) AS member_count,
GROUP_CONCAT(u.id || '::' || u.username, '|||') AS member_pairs
FROM user_groups g
LEFT JOIN user_group_memberships m ON m.group_id = g.id
LEFT JOIN users u ON u.id = m.user_id
GROUP BY g.id
ORDER BY g.name COLLATE NOCASE
`);
const parseMembers = (rawPairs) => {
if (!rawPairs) {
return [];
}
return rawPairs
.split('|||')
.map((entry) => {
const [idPart, usernamePart] = entry.split('::');
const numericId = Number(idPart);
return {
id: Number.isFinite(numericId) ? numericId : idPart,
username: (usernamePart || '').trim()
};
})
.filter((member) => member.username);
};
const sanitizeGroup = (row) => ({
id: row.id,
name: row.name,
description: row.description || '',
createdAt: row.created_at || null,
updatedAt: row.updated_at || null,
memberCount: Number(row.member_count) || 0,
members: parseMembers(row.member_pairs)
});
export function listGroups() {
const rows = selectGroupsWithMembers.all();
return rows.map(sanitizeGroup);
}
+22
View File
@@ -45,6 +45,8 @@ import {
removeServer,
setServerApiKey
} from './setup/index.js';
import { listUsers } from './users/index.js';
import { listGroups } from './groups/index.js';
dotenv.config();
@@ -1671,6 +1673,26 @@ app.get('/api/auth/session', (req, res) => {
res.json({ user: sanitizeUser(user) });
});
app.get('/api/users', (req, res) => {
try {
const users = listUsers();
res.json({ items: users, total: users.length });
} catch (error) {
console.error('⚠️ [Users] Abruf der Benutzerliste fehlgeschlagen:', error);
res.status(500).json({ error: 'USERS_FETCH_FAILED' });
}
});
app.get('/api/groups', (req, res) => {
try {
const groups = listGroups();
res.json({ items: groups, total: groups.length });
} catch (error) {
console.error('⚠️ [Groups] Abruf der Benutzergruppenliste fehlgeschlagen:', error);
res.status(500).json({ error: 'GROUPS_FETCH_FAILED' });
}
});
// Superuser Setup
app.get('/api/auth/superuser/status', (req, res) => {
const exists = hasSuperuser();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -32,8 +32,8 @@
<!-- Nepcha Analytics (nepcha.com) -->
<!-- Nepcha is a easy-to-use web analytics. No cookies and fully compliant with GDPR, CCPA and PECR. -->
<script defer data-site="YOUR_DOMAIN_HERE" src="https://api.nepcha.com/js/nepcha-analytics.js"></script>
<script type="module" crossorigin src="/assets/index-999a8a11.js"></script>
<link rel="stylesheet" href="/assets/index-4350b70a.css">
<script type="module" crossorigin src="/assets/index-af8f32f4.js"></script>
<link rel="stylesheet" href="/assets/index-58708f0f.css">
</head>
<body>
<div id="root"></div>
+44
View File
@@ -0,0 +1,44 @@
import { db } from '../db/index.js';
const selectUsersWithGroups = db.prepare(`
SELECT
u.id,
u.username,
u.email,
u.is_active,
u.last_login,
u.created_at,
u.updated_at,
GROUP_CONCAT(g.name, '|||') AS group_names
FROM users u
LEFT JOIN user_group_memberships m ON m.user_id = u.id
LEFT JOIN user_groups g ON g.id = m.group_id
GROUP BY u.id
ORDER BY u.username COLLATE NOCASE
`);
const normalizeGroupNames = (rawNames) => {
if (!rawNames) {
return [];
}
return rawNames
.split('|||')
.map((name) => String(name || '').trim())
.filter(Boolean);
};
const sanitizeUserRecord = (row) => ({
id: row.id,
username: row.username,
email: row.email,
isActive: Boolean(row.is_active),
lastLogin: row.last_login || null,
createdAt: row.created_at || null,
updatedAt: row.updated_at || null,
groups: normalizeGroupNames(row.group_names)
});
export function listUsers() {
const rows = selectUsersWithGroups.all();
return rows.map(sanitizeUserRecord);
}