ntopng/scripts/lua/modules/blog_utils.lua
Manuel Ceroni 82ec9f289b
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
Fixed the blog posts (#11068)
2026-10-08 13:07:59 +02:00

238 lines
6 KiB
Lua

--
-- (C) 2020-26 - ntop.org
--
require "lua_trace"
require "ntop_utils"
require "lua_utils_gui"
local json = require("dkjson")
local MAX_POSTS = 3
local blog_utils = {}
local BLOG_FEED_KEY = "ntopng.cache.blog_feed"
local BLOG_NEXT_FEED_UPDATE = "ntopng.prefs.next_feed_update"
local JSON_FEED = "https://feed.ntop.org/blog.json"
-- Parse the date array, following this pattern: {yyyy, mm, dd, H, M, S, ...}
-- Return 0 if the date is missing, otherwise it returns the right epoch
function blog_utils.parseDate(date)
if (type(date) ~= "table") then
return 0
end
local year, month, day, hour, minutes = table.unpack(date)
local epoch = os.time({
year = year,
month = month,
day = day,
hour = hour,
min = minutes
})
return epoch
end
function blog_utils.intersectPosts(s1, s2)
-- if there aren't any old post then return the new ones
if (s1[1] == nil) then
return s2
end
-- do integrity check on old set
if (s1[1].epoch == nil) then
return s2
end
-- if there aren't any new post then return the old ones
if (s2[1] == nil) then
return s1
end
local intersected = {}
local j = 1
-- insert the new posts
for i = 1, MAX_POSTS do
if (s2[i].epoch > s1[1].epoch) then
intersected[i] = s2[i]
j = j + 1
end
end
-- insert the olds posts if the array is not full
local k = 1
for i = j, MAX_POSTS do
intersected[i] = s1[k]
k = k + 1
end
return (intersected)
end
function blog_utils.updatePostState(blogNotificationId, username)
if (blogNotificationId == nil) then
return false
end
if (isEmptyString(username)) then
return false
end
local postsJSON = ntop.getPref(BLOG_FEED_KEY)
local posts = {}
if (not isEmptyString(postsJSON)) then
posts = json.decode(postsJSON)
end
local success = false
for _, p in pairs(posts) do
if (p.id == blogNotificationId) then
if (p.users_read == nil) then
p.users_read = {}
end
p.users_read[username] = true
success = true
end
end
ntop.setPref(BLOG_FEED_KEY, json.encode(posts))
return (success)
end
function blog_utils.updateRedis(newPosts)
-- decode older posts from updateRedis
local oldPostsJSON = ntop.getPref(BLOG_FEED_KEY)
local oldPosts = {}
if (not isEmptyString(oldPostsJSON)) then
oldPosts = json.decode(oldPostsJSON)
end
-- intersect two notifications sets and marks the new
local intersected = blog_utils.intersectPosts(oldPosts, newPosts)
-- save the posts inside redis
ntop.setPref(BLOG_FEED_KEY, json.encode(intersected))
end
function blog_utils.fetchLatestPosts()
if ntop.isOffline() then
return
end
local response
local now = os.time()
local next_fetch = ntop.getPref(BLOG_NEXT_FEED_UPDATE)
local debug = false
if (debug) then
traceError(TRACE_NORMAL, TRACE_CONSOLE, "blog_utils.fetchLatestPosts()")
end
if ((next_fetch ~= nil) and (next_fetch ~= "")) then
next_fetch = tonumber(next_fetch)
if (next_fetch > now) then
return
end
end
traceError(TRACE_NORMAL, TRACE_CONSOLE, "Fetching latest ntop blog posts...")
local info = ntop.getInfo()
local url = JSON_FEED.."?id="..(info["pro.systemid"] or "")
.."&edition="..url_encode(info.edition)
.."&version="..url_encode(info.version)
.."&revision="..url_encode(info.revision)
.."&license_type="..url_encode(info["pro.license_type"] or "")
response = ntop.httpGet(url)
if ((response == nil) or (response["CONTENT"] == nil)) then
ntop.setPref(BLOG_NEXT_FEED_UPDATE, now + 300) -- Try again not less than 5 mins
return (false)
end
-- The feed is an RSS converted to JSON, with the posts in 'entries'
local feed = json.decode(response["CONTENT"])
local posts = feed and feed.entries
if ((posts == nil) or table.len(posts) == 0) then
ntop.setPref(BLOG_NEXT_FEED_UPDATE, now + 300) -- Try again not less than 5 mins
return (false)
end
ntop.setPref(BLOG_NEXT_FEED_UPDATE, now + 43200) -- Try again not less than 12 hours
local latest3Posts = {posts[1], posts[2], posts[3]}
local formattedPosts = {}
for i, post in ipairs(latest3Posts) do
if (post ~= nil) then
local postId = tonumber(string.match(post.id or "", "p=(%d+)"))
local postTitle = post.title or ""
local postURL = post.link
local excerpt = post.summary or ""
excerpt = excerpt:gsub("<[^>]+>", ""):gsub("%[&hellip;%]%s*$", "")
local postShortDesc = string.sub(excerpt, 1, 48) .. '...'
local postEpoch = blog_utils.parseDate(post.published_parsed)
local post = {
id = postId,
title = postTitle,
link = postURL,
shortDesc = postShortDesc,
epoch = postEpoch
}
formattedPosts[#formattedPosts + 1] = post
end
end
-- updates redis
blog_utils.updateRedis(formattedPosts)
return (true)
end
function blog_utils.readPostsFromRedis(username)
if (username == nil) then
return {}
end
if (isEmptyString(username)) then
return {}
end
local postsJSON = ntop.getPref(BLOG_FEED_KEY)
local posts = {}
if (not isEmptyString(postsJSON)) then
posts = json.decode(postsJSON)
end
local newPostCounter = 0
-- post.users_read is an array which contains
-- the users who read the notification
for _, post in pairs(posts) do
if (post.users_read == nil) then
post.users_read = {}
newPostCounter = newPostCounter + 1
else
if (not post.users_read[username]) then
newPostCounter = newPostCounter + 1
end
end
end
return posts, newPostCounter
end
return blog_utils