Mercurial > prosody-modules
comparison mod_muc_log/mod_muc_log.lua @ 90:d6521ebea967
mod_muc_log: specified day is now part of the url not a query. days are sorted, newest top.
| author | Thilo Cestonaro <thilo@cestona.ro> |
|---|---|
| date | Tue, 10 Nov 2009 22:53:12 +0100 |
| parents | 24c734c09982 |
| children | 941fd7d8b9b2 |
comparison
equal
deleted
inserted
replaced
| 89:24c734c09982 | 90:d6521ebea967 |
|---|---|
| 2 -- | 2 -- |
| 3 -- This project is MIT/X11 licensed. Please see the | 3 -- This project is MIT/X11 licensed. Please see the |
| 4 -- COPYING file in the source package for more information. | 4 -- COPYING file in the source package for more information. |
| 5 -- | 5 -- |
| 6 local prosody = prosody; | 6 local prosody = prosody; |
| 7 local tabSort = table.sort; | |
| 7 local splitJid = require "util.jid".split; | 8 local splitJid = require "util.jid".split; |
| 8 local bareJid = require "util.jid".bare; | 9 local bareJid = require "util.jid".bare; |
| 9 local config_get = require "core.configmanager".get; | 10 local config_get = require "core.configmanager".get; |
| 10 local httpserver = require "net.httpserver"; | 11 local httpserver = require "net.httpserver"; |
| 11 local serialize = require "util.serialization".serialize; | 12 local serialize = require "util.serialization".serialize; |
| 72 html.rooms.body = [[<h2>Rooms hosted on MUC host: ###COMPONENT###</h2><hr /><p> | 73 html.rooms.body = [[<h2>Rooms hosted on MUC host: ###COMPONENT###</h2><hr /><p> |
| 73 ###ROOMS_STUFF### | 74 ###ROOMS_STUFF### |
| 74 </p><hr />]]; | 75 </p><hr />]]; |
| 75 | 76 |
| 76 html.days = {}; | 77 html.days = {}; |
| 77 html.days.bit = [[<a href="./?year=###YEAR###&month=###MONTH###&day=###DAY###">20###YEAR###/###MONTH###/###DAY###</a><br />]]; | 78 html.days.bit = [[<a href="###BARE_DAY###/">20###YEAR###/###MONTH###/###DAY###</a><br />]]; |
| 78 html.days.body = [[<h2>available logged days of room: ###JID###</h2><hr /><p> | 79 html.days.body = [[<h2>available logged days of room: ###JID###</h2><hr /><p> |
| 79 ###DAYS_STUFF### | 80 ###DAYS_STUFF### |
| 80 </p><hr />]]; | 81 </p><hr />]]; |
| 81 | 82 |
| 82 html.day = {}; | 83 html.day = {}; |
| 98 <input type="checkbox" onclick="showHide('status')" ###STATUS_CHECKED###/>show/hide status changes</button> | 99 <input type="checkbox" onclick="showHide('status')" ###STATUS_CHECKED###/>show/hide status changes</button> |
| 99 <hr /><div id="main" style="overflow: scroll;"> | 100 <hr /><div id="main" style="overflow: scroll;"> |
| 100 ###DAY_STUFF### | 101 ###DAY_STUFF### |
| 101 </div><hr /> | 102 </div><hr /> |
| 102 <script><!-- | 103 <script><!-- |
| 103 document.getElementById("main").style.height = screen.availHeight - 300; | 104 var ele = document.getElementById("main"); |
| 105 ele.style.height = window.innerHeight - ele.offsetTop - 25; | |
| 104 --></script>]]; | 106 --></script>]]; |
| 105 | 107 |
| 106 html.help = [[ | 108 html.help = [[ |
| 107 MUC logging is not configured correctly.<br /> | 109 MUC logging is not configured correctly.<br /> |
| 108 Here is a example config:<br /> | 110 Here is a example config:<br /> |
| 219 end | 221 end |
| 220 return; | 222 return; |
| 221 end | 223 end |
| 222 | 224 |
| 223 function createDoc(body) | 225 function createDoc(body) |
| 224 return html.doc:gsub("###BODY_STUFF###", body); | 226 return html.doc:gsub("###BODY_STUFF###", body or ""); |
| 225 end | 227 end |
| 226 | 228 |
| 227 local function htmlEscape(t) | 229 local function htmlEscape(t) |
| 228 t = t:gsub("<", "<"); | 230 t = t:gsub("<", "<"); |
| 229 t = t:gsub(">", ">"); | 231 t = t:gsub(">", ">"); |
| 231 t = t:gsub("\n", "<br />"); | 233 t = t:gsub("\n", "<br />"); |
| 232 -- TODO do any html escaping stuff ... | 234 -- TODO do any html escaping stuff ... |
| 233 return t; | 235 return t; |
| 234 end | 236 end |
| 235 | 237 |
| 236 function splitQuery(query) | 238 function splitUrl(url) |
| 237 local ret = {}; | |
| 238 local name, value = nil, nil; | |
| 239 if query == nil then return ret; end | |
| 240 local last = 1; | |
| 241 local idx = query:find("&", last); | |
| 242 while idx ~= nil do | |
| 243 name, value = query:sub(last, idx - 1):match("^(%a+)=(%d+)$"); | |
| 244 ret[name] = value; | |
| 245 last = idx + 1; | |
| 246 idx = query:find("&", last); | |
| 247 end | |
| 248 name, value = query:sub(last):match("^(%a+)=(%d+)$"); | |
| 249 ret[name] = value; | |
| 250 return ret; | |
| 251 end | |
| 252 | |
| 253 function grepRoomJid(url) | |
| 254 local tmp = url:sub(string.len("/muc_log/") + 1); | 239 local tmp = url:sub(string.len("/muc_log/") + 1); |
| 240 local day = nil; | |
| 255 local room = nil; | 241 local room = nil; |
| 256 local component = nil; | 242 local component = nil; |
| 257 local at = nil; | 243 local at = nil; |
| 258 local slash = nil; | 244 local slash = nil; |
| 259 local slash2 = nil; | 245 local slash2 = nil; |
| 260 | 246 |
| 261 slash = tmp:find("/"); | 247 slash = tmp:find("/"); |
| 262 if slash ~= nil then | 248 if slash then |
| 263 component = tmp:sub(1, slash - 1); | 249 component = tmp:sub(1, slash - 1); |
| 264 if tmp:len() > slash then | 250 if tmp:len() > slash then |
| 265 room = tmp:sub(slash + 1); | 251 room = tmp:sub(slash + 1); |
| 266 slash = room:find("/"); | 252 slash = room:find("/"); |
| 267 if slash then | 253 if slash then |
| 268 room = room:sub(1, slash - 1); | 254 tmp = room; |
| 269 end | 255 room = tmp:sub(1, slash - 1); |
| 270 module:log("debug", "", room); | 256 if tmp:len() > slash then |
| 271 end | 257 day = tmp:sub(slash + 1); |
| 272 end | 258 slash = day:find("/"); |
| 273 | 259 if slash then |
| 274 module:log("debug", "component: %s; room: %s", tostring(component), tostring(room)); | 260 day = day:sub(1, slash - 1); |
| 275 return room, component; | 261 end |
| 262 end | |
| 263 end | |
| 264 end | |
| 265 end | |
| 266 | |
| 267 return room, component, day; | |
| 276 end | 268 end |
| 277 | 269 |
| 278 local function generateComponentListSiteContent() | 270 local function generateComponentListSiteContent() |
| 279 local components = ""; | 271 local components = ""; |
| 280 for component,muc_host in pairs(muc_hosts) do | 272 for component,muc_host in pairs(muc_hosts) do |
| 284 return html.components.body:gsub("###COMPONENTS_STUFF###", components); | 276 return html.components.body:gsub("###COMPONENTS_STUFF###", components); |
| 285 end | 277 end |
| 286 | 278 |
| 287 local function generateRoomListSiteContent(component) | 279 local function generateRoomListSiteContent(component) |
| 288 local rooms = ""; | 280 local rooms = ""; |
| 289 for host, config in pairs(prosody.hosts) do | 281 if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then |
| 290 if host == component and prosody.hosts[host].muc ~= nil then | 282 for jid, room in pairs(prosody.hosts[component].muc.rooms) do |
| 291 for jid, room in pairs(prosody.hosts[host].muc.rooms) do | 283 local node = splitJid(jid); |
| 292 local node = splitJid(jid); | 284 if not room._data.hidden and node then |
| 293 if not room._data.hidden and node then | 285 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); |
| 294 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", host); | 286 end |
| 295 end | 287 end |
| 296 end | 288 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component); |
| 297 end | 289 end |
| 298 end | 290 return generateComponentListSiteContent(); -- fallback |
| 299 | |
| 300 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component); | |
| 301 end | 291 end |
| 302 | 292 |
| 303 local function generateDayListSiteContentByRoom(bareRoomJid) | 293 local function generateDayListSiteContentByRoom(bareRoomJid) |
| 304 local days = ""; | 294 local days = ""; |
| 295 local arrDays = {}; | |
| 305 local tmp; | 296 local tmp; |
| 306 local node, host, resource = splitJid(bareRoomJid); | 297 local node, host, resource = splitJid(bareRoomJid); |
| 307 local path = data_getpath(node, host, datastore); | 298 local path = data_getpath(node, host, datastore); |
| 308 local room = nil; | 299 local room = nil; |
| 309 local attributes = nil; | 300 local attributes = nil; |
| 320 for file in lfs.dir(path) do | 311 for file in lfs.dir(path) do |
| 321 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)"); | 312 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)"); |
| 322 if year ~= nil and month ~= nil and day ~= nil and | 313 if year ~= nil and month ~= nil and day ~= nil and |
| 323 year ~= "" and month ~= "" and day ~= "" | 314 year ~= "" and month ~= "" and day ~= "" |
| 324 then | 315 then |
| 325 tmp = html.days.bit; | 316 arrDays[#arrDays + 1] = {bare=file, year=year, month=month, day=day}; |
| 326 tmp = tmp:gsub("###ROOM###", node):gsub("###COMPONENT###", host); | 317 end |
| 327 tmp = tmp:gsub("###YEAR###", year):gsub("###MONTH###", month):gsub("###DAY###", day); | 318 end |
| 328 days = tmp .. days; | 319 tabSort(arrDays, function(a,b) |
| 329 end | 320 return a.bare < b.bare; |
| 330 end | 321 end); |
| 331 end | 322 for _, date in pairs(arrDays) do |
| 323 tmp = html.days.bit; | |
| 324 tmp = tmp:gsub("###ROOM###", node):gsub("###COMPONENT###", host); | |
| 325 tmp = tmp:gsub("###BARE_DAY###", date.bare); | |
| 326 tmp = tmp:gsub("###YEAR###", date.year):gsub("###MONTH###", date.month):gsub("###DAY###", date.day); | |
| 327 days = tmp .. days; | |
| 328 end | |
| 329 end | |
| 330 | |
| 332 if days ~= "" then | 331 if days ~= "" then |
| 333 tmp = html.days.body:gsub("###DAYS_STUFF###", days); | 332 tmp = html.days.body:gsub("###DAYS_STUFF###", days); |
| 334 return tmp:gsub("###JID###", bareRoomJid); | 333 return tmp:gsub("###JID###", bareRoomJid); |
| 335 else | 334 else |
| 336 return generateRoomListSiteContent(host); -- fallback | 335 return generateRoomListSiteContent(host); -- fallback |
| 442 ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); | 441 ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); |
| 443 end | 442 end |
| 444 return ret; | 443 return ret; |
| 445 end | 444 end |
| 446 | 445 |
| 447 local function parseDay(bareRoomJid, roomSubject, query) | 446 local function parseDay(bareRoomJid, roomSubject, bare_day) |
| 448 local ret = ""; | 447 local ret = ""; |
| 449 local year; | 448 local year; |
| 450 local month; | 449 local month; |
| 451 local day; | 450 local day; |
| 452 local tmp; | 451 local tmp; |
| 453 local node, host, resource = splitJid(bareRoomJid); | 452 local node, host, resource = splitJid(bareRoomJid); |
| 454 | 453 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); |
| 455 if query.year ~= nil and query.month ~= nil and query.day ~= nil then | 454 |
| 456 local data = data_load(node, host, datastore .. "/" .. query.year .. query.month .. query.day); | 455 if bare_day ~= nil then |
| 456 local data = data_load(node, host, datastore .. "/" .. bare_day); | |
| 457 if data ~= nil then | 457 if data ~= nil then |
| 458 for i=1, #data, 1 do | 458 for i=1, #data, 1 do |
| 459 local stanza = lom.parse(data[i]); | 459 local stanza = lom.parse(data[i]); |
| 460 if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then | 460 if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then |
| 461 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time); | 461 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time); |
| 475 elseif stanza[1].tag == "message" then | 475 elseif stanza[1].tag == "message" then |
| 476 tmp = parseMessageStanza(stanza[1], timeStuff, nick); | 476 tmp = parseMessageStanza(stanza[1], timeStuff, nick); |
| 477 elseif stanza[1].tag == "iq" then | 477 elseif stanza[1].tag == "iq" then |
| 478 tmp = parseIqStanza(stanza[1], timeStuff, nick); | 478 tmp = parseIqStanza(stanza[1], timeStuff, nick); |
| 479 else | 479 else |
| 480 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day); | 480 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day); |
| 481 end | 481 end |
| 482 if tmp ~= nil then | 482 if tmp ~= nil then |
| 483 ret = ret .. tmp | 483 ret = ret .. tmp |
| 484 tmp = nil; | 484 tmp = nil; |
| 485 end | 485 end |
| 488 end | 488 end |
| 489 else | 489 else |
| 490 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback | 490 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback |
| 491 end | 491 end |
| 492 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); | 492 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); |
| 493 tmp = tmp:gsub("###YEAR###", query.year):gsub("###MONTH###", query.month):gsub("###DAY###", query.day); | 493 tmp = tmp:gsub("###YEAR###", year):gsub("###MONTH###", month):gsub("###DAY###", day); |
| 494 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject)); | 494 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject)); |
| 495 tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or ""); | 495 tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or ""); |
| 496 tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or ""); | 496 tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or ""); |
| 497 return tmp; | 497 return tmp; |
| 498 else | 498 else |
| 499 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback | 499 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback |
| 500 end | 500 end |
| 501 end | 501 end |
| 502 | 502 |
| 503 --[[ | |
| 504 local function loggingMucComponents() | |
| 505 local n = 0; | |
| 506 for component,_ in pairs(muc_hosts) do | |
| 507 n = n + 1; | |
| 508 end | |
| 509 return n; | |
| 510 end | |
| 511 ]]-- | |
| 512 | |
| 503 function handle_request(method, body, request) | 513 function handle_request(method, body, request) |
| 504 local query = splitQuery(request.url.query); | 514 -- local query = splitQuery(request.url.query); |
| 505 local node, host = grepRoomJid(request.url.path); | 515 local node, host, day = splitUrl(request.url.path); |
| 516 --[[if host == nil and loggingMucComponents() == 1 then | |
| 517 for component,_ in pairs(muc_hosts) do | |
| 518 host = component; | |
| 519 break; | |
| 520 end | |
| 521 module:log("debug", "host: %s", tostring(host)); | |
| 522 end]]-- | |
| 506 | 523 |
| 507 if node ~= nil and host ~= nil then | 524 if node ~= nil and host ~= nil then |
| 508 local bare = node .. "@" .. host; | 525 local bare = node .. "@" .. host; |
| 509 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then | 526 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil then |
| 510 local room = prosody.hosts[host].muc.rooms[bare]; | 527 if prosody.hosts[host].muc.rooms[bare] ~= nil then |
| 511 if request.url.query == nil then | 528 local room = prosody.hosts[host].muc.rooms[bare]; |
| 512 return createDoc(generateDayListSiteContentByRoom(bare)); | 529 if day == nil then |
| 530 return createDoc(generateDayListSiteContentByRoom(bare)); | |
| 531 else | |
| 532 local subject = "" | |
| 533 if room._data ~= nil and room._data.subject ~= nil then | |
| 534 subject = room._data.subject; | |
| 535 end | |
| 536 return createDoc(parseDay(bare, subject, day)); | |
| 537 end | |
| 513 else | 538 else |
| 514 local subject = "" | 539 return createDoc(generateRoomListSiteContent(host)); |
| 515 if room._data ~= nil and room._data.subject ~= nil then | 540 end |
| 516 subject = room._data.subject; | 541 else |
| 517 end | 542 return createDoc(generateComponentListSiteContent()); |
| 518 return createDoc(parseDay(bare, subject, query)); | |
| 519 end | |
| 520 end | 543 end |
| 521 elseif host ~= nil then | 544 elseif host ~= nil then |
| 522 return createDoc(generateRoomListSiteContent(host)); | 545 return createDoc(generateRoomListSiteContent(host)); |
| 523 else | 546 else |
| 524 module:log("debug", "build component list site content") | |
| 525 return createDoc(generateComponentListSiteContent()); | 547 return createDoc(generateComponentListSiteContent()); |
| 526 end | 548 end |
| 527 return; | 549 return; |
| 528 end | 550 end |
| 529 | 551 |
| 530 function module.load() | 552 function module.load() |
| 531 config = config_get("*", "core", "muc_log") or {}; | 553 config = config_get("*", "core", "muc_log") or {}; |
| 532 config.showStatus = config.showStatus or true; | 554 if config.showStatus == nil then |
| 533 config.showJoin = config.showJoin or true; | 555 config.showStatus = true; |
| 556 end | |
| 557 if config.showJoin == nil then | |
| 558 config.showJoin = true; | |
| 559 end | |
| 534 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = "muc_log" }); | 560 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = "muc_log" }); |
| 535 | 561 |
| 536 for jid, host in pairs(prosody.hosts) do | 562 for jid, host in pairs(prosody.hosts) do |
| 537 if host.muc then | 563 if host.muc then |
| 538 local logging = config_get(jid, "core", "logging"); | 564 local logging = config_get(jid, "core", "logging"); |
| 539 if logging then | 565 if logging then |
| 540 module:log("debug", "Component enabled: %s", jid); | 566 module:log("debug", "component: %s", tostring(jid)); |
| 541 muc_hosts[jid] = true; | 567 muc_hosts[jid] = true; |
| 542 end | 568 end |
| 543 end | 569 end |
| 544 end | 570 end |
| 545 end | 571 end |
| 548 muc_hosts = nil; | 574 muc_hosts = nil; |
| 549 end | 575 end |
| 550 | 576 |
| 551 module:add_event_hook("component-activated", function(component, config) | 577 module:add_event_hook("component-activated", function(component, config) |
| 552 if config.core.logging == true then | 578 if config.core.logging == true then |
| 553 module:log("debug", "Component enabled: %s", component); | 579 module:log("debug", "component: %s", tostring(component)); |
| 554 muc_hosts[component] = true; | 580 muc_hosts[component] = true; |
| 555 end | 581 end |
| 556 end); | 582 end); |
| 557 | 583 |
| 558 module:hook("message/bare", logIfNeeded, 500); | 584 module:hook("message/bare", logIfNeeded, 500); |
