Polish user actions and runtime controls

This commit is contained in:
2026-04-02 02:51:32 +03:00
parent c04847b21c
commit 3adda67eb9
9 changed files with 556 additions and 85 deletions

View File

@@ -94,18 +94,26 @@ export function createApp({ store, runtime, runtimeRootDir, auth, liveSync }: Ap
try {
const state = await store.read();
const action = request.params.action;
const controller = action === 'restart' ? runtime.restart.bind(runtime) : runtime.start.bind(runtime);
const controller =
action === 'restart'
? runtime.restart.bind(runtime)
: action === 'stop'
? runtime.stop.bind(runtime)
: runtime.start.bind(runtime);
if (!['start', 'restart'].includes(action)) {
if (!['start', 'restart', 'stop'].includes(action)) {
response.status(404).json({ error: 'Unknown runtime action.' });
return;
}
const runtimeSnapshot = await controller();
state.service.lastEvent = action === 'restart' ? 'Runtime restarted from panel' : 'Runtime start requested from panel';
if (runtimeSnapshot.startedAt) {
state.service.startedAt = runtimeSnapshot.startedAt;
}
state.service.lastEvent =
action === 'restart'
? 'Runtime restarted from panel'
: action === 'stop'
? 'Runtime stop requested from panel'
: 'Runtime start requested from panel';
state.service.startedAt = runtimeSnapshot.startedAt ?? null;
await writeConfigAndState(store, state, runtimePaths);
liveSync?.notifyPotentialChange();
@@ -130,6 +138,40 @@ export function createApp({ store, runtime, runtimeRootDir, auth, liveSync }: Ap
}
});
app.put('/api/users/:id', async (request, response, next) => {
try {
const state = await store.read();
const user = state.userRecords.find((entry) => entry.id === request.params.id);
if (!user) {
response.status(404).json({ error: 'User not found.' });
return;
}
const input = validateCreateUserInput(request.body as Partial<CreateUserInput>, state.system.services);
const duplicateUser = state.userRecords.find(
(entry) => entry.id !== user.id && entry.username.toLowerCase() === input.username.toLowerCase(),
);
if (duplicateUser) {
response.status(400).json({ error: 'Username already exists.' });
return;
}
user.username = input.username;
user.password = input.password;
user.serviceId = input.serviceId;
user.quotaBytes = input.quotaMb === null ? null : input.quotaMb * 1024 * 1024;
state.service.lastEvent = `User ${user.username} updated from panel`;
await persistRuntimeMutation(store, runtime, state, runtimePaths);
liveSync?.notifyPotentialChange();
response.json(await getDashboardSnapshot(store, runtime, runtimePaths));
} catch (error) {
next(error);
}
});
app.put('/api/system', async (request, response, next) => {
try {
const state = await store.read();