mirror of
https://github.com/RaisFast/raisfast.git
synced 2026-09-25 08:02:36 +00:00
162 lines
5.3 KiB
Lua
162 lines
5.3 KiB
Lua
-- Blog Stats API Plugin
|
|
--
|
|
-- 通过 handle_route hook 注册自定义 REST 端点,暴露博客统计数据。
|
|
-- 所有数据通过 dbQuery (SELECT) 从数据库读取。
|
|
--
|
|
-- 端点:
|
|
-- GET /api/v1/plugins/stats/overview — 博客总览(文章/评论/用户数量)
|
|
-- GET /api/v1/plugins/stats/posts — 文章统计(按状态分组)
|
|
-- GET /api/v1/plugins/stats/recent — 最近发布的文章列表
|
|
-- GET /api/v1/plugins/stats/top — 浏览量排行
|
|
|
|
-- ── 工具函数 ──────────────────────────────────────────────────
|
|
|
|
local function json_response(status, data)
|
|
return {
|
|
status = status,
|
|
body = '{' .. '"code":0,"message":"ok","data":' .. data .. '}'
|
|
}
|
|
end
|
|
|
|
local function error_response(status, msg)
|
|
return {
|
|
status = status,
|
|
body = '{"code":' .. status .. '00,"message":"' .. msg .. '","data":null}'
|
|
}
|
|
end
|
|
|
|
-- 安全地从 dbQuery 结果中提取 JSON 数组字符串
|
|
-- dbQuery 返回格式: [{"col1":"val1","col2":"val2"}, ...]
|
|
local function query(sql)
|
|
local result = Host.dbQuery(sql)
|
|
if not result then
|
|
return nil, "query failed"
|
|
end
|
|
-- dbQuery 错误时返回 "error: ..."
|
|
if result:sub(1, 6) == "error:" then
|
|
return nil, result
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- ── 路由处理 ──────────────────────────────────────────────────
|
|
|
|
-- GET /api/v1/plugins/stats/overview
|
|
-- 博客总览:文章数、评论数、用户数
|
|
local function handle_overview()
|
|
local posts_json, err = query("SELECT COUNT(*) as total FROM posts")
|
|
if not posts_json then
|
|
return error_response(500, err)
|
|
end
|
|
|
|
local comments_json, _ = query("SELECT COUNT(*) as total FROM comments")
|
|
local users_json, _ = query("SELECT COUNT(*) as total FROM users")
|
|
local published_json, _ = query("SELECT COUNT(*) as total FROM posts WHERE status = 'published'")
|
|
|
|
-- 提取计数值
|
|
local total_posts = tonumber(posts_json:match('"total":"?(%d+)"?')) or 0
|
|
local total_comments = 0
|
|
local total_users = 0
|
|
local total_published = 0
|
|
|
|
if comments_json then
|
|
total_comments = tonumber(comments_json:match('"total":"?(%d+)"?')) or 0
|
|
end
|
|
if users_json then
|
|
total_users = tonumber(users_json:match('"total":"?(%d+)"?')) or 0
|
|
end
|
|
if published_json then
|
|
total_published = tonumber(published_json:match('"total":"?(%d+)"?')) or 0
|
|
end
|
|
|
|
local data = '{'
|
|
.. '"total_posts":' .. total_posts .. ','
|
|
.. '"total_published":' .. total_published .. ','
|
|
.. '"total_comments":' .. total_comments .. ','
|
|
.. '"total_users":' .. total_users
|
|
.. '}'
|
|
|
|
return json_response(200, data)
|
|
end
|
|
|
|
-- GET /api/v1/plugins/stats/posts
|
|
-- 按状态统计文章数量
|
|
local function handle_posts_stats()
|
|
local result, err = query("SELECT status, COUNT(*) as count FROM posts GROUP BY status")
|
|
if not result then
|
|
return error_response(500, err)
|
|
end
|
|
|
|
-- result 已经是 JSON 数组,直接包装
|
|
return json_response(200, result)
|
|
end
|
|
|
|
-- GET /api/v1/plugins/stats/recent
|
|
-- 最近发布的 10 篇文章
|
|
local function handle_recent()
|
|
local result, err = query(
|
|
"SELECT title, slug, view_count, published_at "
|
|
.. "FROM posts WHERE status = 'published' "
|
|
.. "ORDER BY published_at DESC LIMIT 10"
|
|
)
|
|
if not result then
|
|
return error_response(500, err)
|
|
end
|
|
|
|
return json_response(200, result)
|
|
end
|
|
|
|
-- GET /api/v1/plugins/stats/top
|
|
-- 浏览量最高的 10 篇文章
|
|
local function handle_top()
|
|
local result, err = query(
|
|
"SELECT title, slug, view_count "
|
|
.. "FROM posts WHERE status = 'published' "
|
|
.. "ORDER BY view_count DESC LIMIT 10"
|
|
)
|
|
if not result then
|
|
return error_response(500, err)
|
|
end
|
|
|
|
return json_response(200, result)
|
|
end
|
|
|
|
-- ── 路由匹配 ──────────────────────────────────────────────────
|
|
|
|
-- 简单的路由表:路径后缀 → 处理函数
|
|
local routes = {
|
|
["overview"] = handle_overview,
|
|
["posts"] = handle_posts_stats,
|
|
["recent"] = handle_recent,
|
|
["top"] = handle_top,
|
|
}
|
|
|
|
-- ── Hook 入口 ─────────────────────────────────────────────────
|
|
|
|
Plugin = {
|
|
handle_route = function(input)
|
|
local path = input.path or ""
|
|
local method = input.method or ""
|
|
|
|
-- 只处理 GET 请求
|
|
if method ~= "GET" then
|
|
return nil
|
|
end
|
|
|
|
-- 从路径中提取最后一段作为路由名
|
|
-- /api/v1/plugins/stats/overview → "overview"
|
|
local route_name = path:match("/api/v1/plugins/stats/([^/]+)$")
|
|
if not route_name then
|
|
return nil
|
|
end
|
|
|
|
local handler = routes[route_name]
|
|
if not handler then
|
|
return error_response(404, "unknown endpoint: " .. route_name)
|
|
end
|
|
|
|
Host.log("info", "[blog-stats] " .. method .. " " .. path)
|
|
return handler()
|
|
end,
|
|
}
|