From 44b9fbb0985404a94e09332dd0eaca2d96405729 Mon Sep 17 00:00:00 2001 From: JohnDoe6345789 Date: Fri, 26 Dec 2025 01:26:35 +0000 Subject: [PATCH] docs: dbal,hpp,cpp (5 files) --- .../src/entities/session/clean_expired.hpp | 8 ++-- .../src/entities/session/list_sessions.hpp | 44 +++++++++++-------- .../validate-lua-script-update.test.ts | 1 + docs/permissions-levels.md | 1 + .../nextjs/src/app/api/health/route.test.tsx | 14 ++++++ 5 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 frontends/nextjs/src/app/api/health/route.test.tsx diff --git a/dbal/cpp/src/entities/session/clean_expired.hpp b/dbal/cpp/src/entities/session/clean_expired.hpp index 6308d8a8c..3bb654a9f 100644 --- a/dbal/cpp/src/entities/session/clean_expired.hpp +++ b/dbal/cpp/src/entities/session/clean_expired.hpp @@ -21,13 +21,13 @@ namespace session { inline Result cleanExpired(InMemoryStore& store) { auto now = std::chrono::system_clock::now(); std::vector expired_ids; - + for (const auto& [id, session] : store.sessions) { - if (session.expires_at < now) { + if (session.expires_at <= now) { expired_ids.push_back(id); } } - + for (const auto& id : expired_ids) { auto it = store.sessions.find(id); if (it != store.sessions.end()) { @@ -35,7 +35,7 @@ inline Result cleanExpired(InMemoryStore& store) { store.sessions.erase(it); } } - + return Result(static_cast(expired_ids.size())); } diff --git a/dbal/cpp/src/entities/session/list_sessions.hpp b/dbal/cpp/src/entities/session/list_sessions.hpp index a03bbdc13..03f454fc6 100644 --- a/dbal/cpp/src/entities/session/list_sessions.hpp +++ b/dbal/cpp/src/entities/session/list_sessions.hpp @@ -1,6 +1,6 @@ /** * @file list_sessions.hpp - * @brief List sessions with filtering + * @brief List sessions with filtering and pagination */ #ifndef DBAL_LIST_SESSIONS_HPP #define DBAL_LIST_SESSIONS_HPP @@ -8,6 +8,7 @@ #include "dbal/types.hpp" #include "dbal/errors.hpp" #include "../../store/in_memory_store.hpp" +#include "clean_expired.hpp" #include namespace dbal { @@ -18,36 +19,43 @@ namespace session { * List sessions with filtering and pagination */ inline Result> list(InMemoryStore& store, const ListOptions& options) { + cleanExpired(store); + std::vector sessions; - auto now = std::chrono::system_clock::now(); - + for (const auto& [id, session] : store.sessions) { bool matches = true; - + if (options.filter.find("user_id") != options.filter.end()) { if (session.user_id != options.filter.at("user_id")) matches = false; } - - if (options.filter.find("active_only") != options.filter.end()) { - if (options.filter.at("active_only") == "true" && session.expires_at < now) { - matches = false; - } + + if (options.filter.find("token") != options.filter.end()) { + if (session.token != options.filter.at("token")) matches = false; + } + + if (matches) { + sessions.push_back(session); } - - if (matches) sessions.push_back(session); } - - std::sort(sessions.begin(), sessions.end(), [](const Session& a, const Session& b) { - return a.created_at > b.created_at; - }); - + + if (options.sort.find("created_at") != options.sort.end()) { + std::sort(sessions.begin(), sessions.end(), [](const Session& a, const Session& b) { + return a.created_at < b.created_at; + }); + } else if (options.sort.find("expires_at") != options.sort.end()) { + std::sort(sessions.begin(), sessions.end(), [](const Session& a, const Session& b) { + return a.expires_at < b.expires_at; + }); + } + int start = (options.page - 1) * options.limit; int end = std::min(start + options.limit, static_cast(sessions.size())); - + if (start < static_cast(sessions.size())) { return Result>(std::vector(sessions.begin() + start, sessions.begin() + end)); } - + return Result>(std::vector()); } diff --git a/dbal/ts/tests/core/validation/validate-lua-script-update.test.ts b/dbal/ts/tests/core/validation/validate-lua-script-update.test.ts index 9306cf4b1..c80cddd49 100644 --- a/dbal/ts/tests/core/validation/validate-lua-script-update.test.ts +++ b/dbal/ts/tests/core/validation/validate-lua-script-update.test.ts @@ -12,6 +12,7 @@ describe('validateLuaScriptUpdate', () => { it.each([ { data: { timeoutMs: 10 }, message: 'timeoutMs must be an integer between 100 and 30000' }, { data: { allowedGlobals: ['ok', 1 as unknown as string] }, message: 'allowedGlobals must contain non-empty strings' }, + { data: { allowedGlobals: ['os'] }, message: 'allowedGlobals contains forbidden globals: os' }, { data: { isSandboxed: 'yes' as unknown as boolean }, message: 'isSandboxed must be a boolean' }, ])('rejects invalid case', ({ data, message }) => { expect(validateLuaScriptUpdate(data)).toContain(message) diff --git a/docs/permissions-levels.md b/docs/permissions-levels.md index 8bcf52e08..ed6645919 100644 --- a/docs/permissions-levels.md +++ b/docs/permissions-levels.md @@ -23,6 +23,7 @@ Visit `/levels` to step through each tier. The page renders a grid of cards, hig - Provide `?cap=` (comma-separated) to return only levels whose capability descriptions mention the given keywords. - `POST /api/levels` accepts a `{ level, note }` payload for telemetry and responds with the matched landing tier. - `GET /api/levels/metrics` returns totals and capability counts so dashboards can include quick diagnostics. +- `GET /api/health` reports service readiness plus the current number of defined levels. ## Tooling diff --git a/frontends/nextjs/src/app/api/health/route.test.tsx b/frontends/nextjs/src/app/api/health/route.test.tsx new file mode 100644 index 000000000..4db343d2b --- /dev/null +++ b/frontends/nextjs/src/app/api/health/route.test.tsx @@ -0,0 +1,14 @@ +import { describe, expect, it } from 'vitest' + +import { GET } from './route' + +describe('GET /api/health', () => { + it('returns OK status and permission level count', async () => { + const response = await GET(new Request('http://example.com/api/health')) + const payload = await response.json() + + expect(payload.status).toBe('ok') + expect(typeof payload.timestamp).toBe('string') + expect(payload.levelCount).toBeGreaterThan(0) + }) +})