release(secrets-mcp): 0.5.4 — Web 分页修正与 hex 解码;批量删除上限;MCP @ 路径检测
This commit is contained in:
@@ -199,6 +199,15 @@ fn request_user_agent(headers: &HeaderMap) -> Option<String> {
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
fn paginate(page: u32, total_count: i64, page_size: u32) -> (u32, u32, u32) {
|
||||
let page_size = page_size.max(1);
|
||||
let safe_total_count = u32::try_from(total_count.max(0)).unwrap_or(u32::MAX);
|
||||
let total_pages = safe_total_count.div_ceil(page_size).max(1);
|
||||
let current_page = page.max(1).min(total_pages);
|
||||
let offset = (current_page - 1).saturating_mul(page_size);
|
||||
(current_page, total_pages, offset)
|
||||
}
|
||||
|
||||
// ── Routes ────────────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn web_router() -> Router<AppState> {
|
||||
@@ -605,8 +614,7 @@ async fn entries_page(
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|s| s.to_string());
|
||||
let page = q.page.unwrap_or(1).max(1);
|
||||
let offset = (page - 1) * ENTRIES_PAGE_LIMIT;
|
||||
let params = SearchParams {
|
||||
let count_params = SearchParams {
|
||||
folder: folder_filter.as_deref(),
|
||||
entry_type: type_filter.as_deref(),
|
||||
name: None,
|
||||
@@ -615,18 +623,22 @@ async fn entries_page(
|
||||
query: None,
|
||||
sort: "updated",
|
||||
limit: ENTRIES_PAGE_LIMIT,
|
||||
offset,
|
||||
offset: 0,
|
||||
user_id: Some(user_id),
|
||||
};
|
||||
|
||||
let total_count = count_entries(&state.pool, ¶ms)
|
||||
let total_count = count_entries(&state.pool, &count_params)
|
||||
.await
|
||||
.inspect_err(|e| tracing::warn!(error = %e, "count_entries failed for web entries page"))
|
||||
.unwrap_or(0);
|
||||
let total_pages = (total_count as u32).div_ceil(ENTRIES_PAGE_LIMIT).max(1);
|
||||
let current_page = page.min(total_pages);
|
||||
let (current_page, total_pages, offset) = paginate(page, total_count, ENTRIES_PAGE_LIMIT);
|
||||
|
||||
let rows = list_entries(&state.pool, params).await.map_err(|e| {
|
||||
let list_params = SearchParams {
|
||||
offset,
|
||||
..count_params
|
||||
};
|
||||
|
||||
let rows = list_entries(&state.pool, list_params).await.map_err(|e| {
|
||||
tracing::error!(error = %e, "failed to load entries list for web");
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
@@ -846,11 +858,8 @@ async fn audit_page(
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
let total_pages = (total_count as u32)
|
||||
.div_ceil(AUDIT_PAGE_LIMIT as u32)
|
||||
.max(1);
|
||||
let current_page = page.min(total_pages);
|
||||
let actual_offset = ((current_page - 1) as i64) * AUDIT_PAGE_LIMIT;
|
||||
let (current_page, total_pages, offset) = paginate(page, total_count, AUDIT_PAGE_LIMIT as u32);
|
||||
let actual_offset = i64::from(offset);
|
||||
|
||||
let rows = list_for_user(&state.pool, user_id, AUDIT_PAGE_LIMIT, actual_offset)
|
||||
.await
|
||||
@@ -1751,4 +1760,29 @@ mod tests {
|
||||
|
||||
assert!(matches!(request_ui_lang(&headers), UiLang::ZhTw));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paginate_clamps_page_before_computing_offset() {
|
||||
let (current_page, total_pages, offset) = paginate(100, 12, 10);
|
||||
|
||||
assert_eq!(current_page, 2);
|
||||
assert_eq!(total_pages, 2);
|
||||
assert_eq!(offset, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paginate_handles_large_page_without_overflow() {
|
||||
let (current_page, total_pages, offset) = paginate(u32::MAX, 1, ENTRIES_PAGE_LIMIT);
|
||||
|
||||
assert_eq!(current_page, 1);
|
||||
assert_eq!(total_pages, 1);
|
||||
assert_eq!(offset, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paginate_saturates_large_total_count() {
|
||||
let (_, total_pages, _) = paginate(1, i64::MAX, ENTRIES_PAGE_LIMIT);
|
||||
|
||||
assert_eq!(total_pages, u32::MAX.div_ceil(ENTRIES_PAGE_LIMIT));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user