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("<", "&lt;"); 230 t = t:gsub("<", "&lt;");
229 t = t:gsub(">", "&gt;"); 231 t = t:gsub(">", "&gt;");
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);