Software /
code /
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 |
parent | 89:24c734c09982 |
child | 94: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); |