Mercurial > prosody-modules
comparison mod_muc_log_http/muc_log_http/mod_muc_log_http.lua @ 972:61b63affd402
mod_muc_log_http: more proper 0.9 port.
author | Marco Cirillo <maranda@lightwitch.org> |
---|---|
date | Sun, 07 Apr 2013 12:54:33 +0200 |
parents | adcb751f22f3 |
children | 1db6d5028b3d |
comparison
equal
deleted
inserted
replaced
971:53e158e44a44 | 972:61b63affd402 |
---|---|
1 -- Copyright (C) 2009 Thilo Cestonaro | |
2 -- | |
3 -- This project is MIT/X11 licensed. Please see the | |
4 -- COPYING file in the source package for more information. | |
5 -- | |
6 | |
7 module:set_global(); | |
8 | |
9 module:depends("http"); | 1 module:depends("http"); |
10 | 2 |
11 local prosody = prosody; | 3 local prosody = prosody; |
4 local my_host = module:get_host(); | |
12 local tabSort = table.sort; | 5 local tabSort = table.sort; |
13 local tonumber = _G.tonumber; | 6 local tonumber = _G.tonumber; |
14 local tostring = _G.tostring; | 7 local tostring = _G.tostring; |
15 local strchar = string.char; | 8 local strchar = string.char; |
16 local strformat = string.format; | 9 local strformat = string.format; |
17 local splitJid = require "util.jid".split; | 10 local splitJid = require "util.jid".split; |
18 local config_get = require "core.configmanager".get; | 11 local config_get = require "core.configmanager".get; |
19 local httpserver = require "net.httpserver"; | |
20 local urlencode = require "net.http".urlencode; | 12 local urlencode = require "net.http".urlencode; |
21 local urldecode = require "net.http".urldecode; | 13 local urldecode = require "net.http".urldecode; |
22 local datamanager = require "util.datamanager"; | 14 local http_event = require "net.http.server".fire_server_event; |
23 local data_load, data_getpath = datamanager.load, datamanager.getpath; | 15 local data_load, data_getpath = datamanager.load, datamanager.getpath; |
24 local datastore = "muc_log"; | 16 local datastore = "muc_log"; |
17 local urlBase = "muc_log"; | |
25 local config = nil; | 18 local config = nil; |
26 local tostring = _G.tostring; | 19 local tostring = _G.tostring; |
27 local tonumber = _G.tonumber; | 20 local tonumber = _G.tonumber; |
28 local os_date, os_time = os.date, os.time; | 21 local os_date, os_time = os.date, os.time; |
29 local str_format = string.format; | 22 local str_format = string.format; |
30 local io_open = io.open; | 23 local io_open = io.open; |
31 local themesParent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes"; | 24 local themesParent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes"; |
32 | 25 |
33 local lom = require "lxp.lom"; | 26 local lom = require "lxp.lom"; |
34 | |
35 --[[ LuaFileSystem | |
36 * URL: http://www.keplerproject.org/luafilesystem/index.html | |
37 * Install: luarocks install luafilesystem | |
38 * ]] | |
39 local lfs = require "lfs"; | 27 local lfs = require "lfs"; |
40 | |
41 | |
42 --[[ | |
43 * Default templates for the html output. | |
44 ]]-- | |
45 local html = {}; | 28 local html = {}; |
46 local theme; | 29 local theme; |
47 | 30 |
48 local function checkDatastorePathExists(node, host, today, create) | 31 local function checkDatastorePathExists(node, host, today, create) |
49 create = create or false; | 32 create = create or false; |
85 end | 68 end |
86 return t; | 69 return t; |
87 end | 70 end |
88 | 71 |
89 function createDoc(body, title) | 72 function createDoc(body, title) |
90 if not body then | 73 if not body then return "" end |
91 return 404; | |
92 end | |
93 body = body:gsub("%%", "%%%%"); | 74 body = body:gsub("%%", "%%%%"); |
94 return html.doc:gsub("###BODY_STUFF###", body) | 75 return html.doc:gsub("###BODY_STUFF###", body) |
95 :gsub("<title>muc_log</title>", "<title>"..(title and htmlEscape(title) or "Chatroom logs").."</title>"); | 76 :gsub("<title>muc_log</title>", "<title>"..(title and htmlEscape(title) or "Chatroom logs").."</title>"); |
96 end | 77 end |
97 | 78 |
98 function urlunescape (escapedUrl) | 79 function urlunescape (escapedUrl) |
99 escapedUrl = escapedUrl:gsub("+", " ") | 80 escapedUrl = escapedUrl:gsub("+", " ") |
100 escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) | 81 escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) |
101 escapedUrl = escapedUrl:gsub("\r\n", "\n") | 82 escapedUrl = escapedUrl:gsub("\r\n", "\n") |
102 return escapedUrl | 83 return escapedUrl |
103 end | |
104 | |
105 local function generateComponentListSiteContent() | |
106 local components = ""; | |
107 for component,host in pairs(hosts) do | |
108 if host.modules.muc and host.modules.muc_log then | |
109 components = components .. html.components.bit:gsub("###COMPONENT###", component); | |
110 end | |
111 end | |
112 return (html.components.body:gsub("###COMPONENTS_STUFF###", components)); | |
113 end | 84 end |
114 | 85 |
115 local function generateRoomListSiteContent(component) | 86 local function generateRoomListSiteContent(component) |
116 local rooms = ""; | 87 local rooms = ""; |
117 if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then | 88 if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then |
293 end | 264 end |
294 end | 265 end |
295 | 266 |
296 room = prosody.hosts[host].muc.rooms[bareRoomJid]; | 267 room = prosody.hosts[host].muc.rooms[bareRoomJid]; |
297 if room._data.hidden then | 268 if room._data.hidden then |
298 room = nil | 269 room = nil; |
299 end | 270 end |
300 end | 271 end |
301 if attributes ~= nil and room ~= nil then | 272 if attributes ~= nil and room ~= nil then |
302 local alreadyDoneYears = {}; | 273 local alreadyDoneYears = {}; |
303 topic = room._data.subject or "(no subject)" | 274 topic = room._data.subject or "(no subject)" |
642 return tmp, "Chatroom logs for "..bareRoomJid.." ("..tostring(os_date("%A, %B %d, %Y", os_time(temptime)))..")"; | 613 return tmp, "Chatroom logs for "..bareRoomJid.." ("..tostring(os_date("%A, %B %d, %Y", os_time(temptime)))..")"; |
643 end | 614 end |
644 end | 615 end |
645 end | 616 end |
646 | 617 |
647 function handle_request(event, path) | 618 local function handle_error(code, err) return http_event("http-error", { code = code, message = err }); end |
648 local request, response = event.request, event.response; | 619 function handle_request(event) |
649 local host, node, day, more = path:match("^([^/]*)/?([^/]*)/?([^/]*)/?(.*)$"); | 620 local response = event.response; |
650 if more ~= "" then return 404; end | 621 local request = event.request; |
651 if host == "" then host = nil; end | 622 local room; |
623 | |
624 local node, day, more = request.url.path:match("^/"..urlBase.."/+([^/]*)/*([^/]*)/*(.*)$"); | |
625 if more ~= "" then | |
626 response.status_code = 404; | |
627 return response:send(handle_error(response.status_code, "Unknown URL.")); | |
628 end | |
652 if node == "" then node = nil; end | 629 if node == "" then node = nil; end |
653 if day == "" then day = nil; end | 630 if day == "" then day = nil; end |
654 | 631 |
655 node = urldecode(node); | 632 node = urldecode(node); |
656 | 633 |
657 if not html.doc then | 634 if not html.doc then |
658 response.status_code = 500; | 635 response.status_code = 500; |
659 return "MUC hosts or theme not loaded"; | 636 return response:send(handle_error(response.status_code, "Muc Theme is not loaded.")); |
660 end | 637 end |
661 | 638 |
662 if host and not(hosts[host] and hosts[host].modules.muc and hosts[host].modules.muc_log) then | 639 |
640 if node then room = hosts[my_host].modules.muc.rooms[node.."@"..my_host]; end | |
641 if node and not room then | |
663 response.status_code = 404; | 642 response.status_code = 404; |
664 return "No such MUC component"; | 643 return response:send(handle_error(response.status_code, "Room doesn't exist.")); |
665 end | 644 end |
666 if host and node and not(hosts[host].modules.muc.rooms[node.."@"..host]) then | 645 if room and room._data.hidden then |
667 response.status_code = 404; | 646 response.status_code = 404; |
668 return "No such MUC room"; | 647 return response:send(handle_error(response.status_code, "There're no logs for this room.")); |
669 end | 648 end |
670 | 649 |
671 if not host then -- main component list | 650 |
672 return createDoc(generateComponentListSiteContent()); | 651 if not node then -- room list for component |
673 elseif not node then -- room list for component | 652 return response:send(createDoc(generateRoomListSiteContent(my_host))); |
674 return createDoc(generateRoomListSiteContent(host)); | |
675 elseif not day then -- room's listing | 653 elseif not day then -- room's listing |
676 return createDoc(generateDayListSiteContentByRoom(node.."@"..host)); | 654 return response:send(createDoc(generateDayListSiteContentByRoom(node.."@"..my_host))); |
677 else | 655 else |
678 if not day:match("^20(%d%d)-(%d%d)-(%d%d)$") then | 656 if not day:match("^20(%d%d)-(%d%d)-(%d%d)$") then |
679 local y,m,d = day:match("^(%d%d)(%d%d)(%d%d)$"); | 657 local y,m,d = day:match("^(%d%d)(%d%d)(%d%d)$"); |
680 if not y then | 658 if not y then |
681 return 404; | 659 response.status_code = 404; |
682 end | 660 return response:send(handle_error(response.status_code, "No entries for that year.")); |
683 response.headers.location = request.path .. "../20"..y.."-"..m.."-"..d.."/"; | 661 end |
684 return 301; | 662 response.status_code = 301; |
685 end | 663 response.headers = { ["Location"] = request.url.path:match("^/"..urlBase.."/+[^/]*").."/20"..y.."-"..m.."-"..d.."/" }; |
686 local room = hosts[host].modules.muc.rooms[node.."@"..host]; | 664 return response:send(); |
687 return createDoc(parseDay(node.."@"..host, room._data.subject or "", day)); | 665 end |
666 | |
667 local body = createDoc(parseDay(node.."@"..my_host, room._data.subject or "", day)); | |
668 if body == "" then | |
669 response.status_code = 404; | |
670 return response:send(handle_error(response.status_code, "Day entry doesn't exist.")); | |
671 end | |
672 return response:send(body); | |
688 end | 673 end |
689 end | 674 end |
690 | 675 |
691 local function readFile(filepath) | 676 local function readFile(filepath) |
692 local f,err = io_open(filepath, "r"); | 677 local f,err = io_open(filepath, "r"); |
713 end | 698 end |
714 end | 699 end |
715 return true; | 700 return true; |
716 end | 701 end |
717 | 702 |
718 function module.add_host(module) | 703 function module.load() |
719 config = config_get("*", "core", "muc_log_http") or {}; | 704 config = module:get_option_table("muc_log_http_config", {}); |
720 if config.showStatus == nil then | 705 if config.showStatus == nil then config.showStatus = true; end |
721 config.showStatus = true; | 706 if config.showJoin == nil then config.showJoin = true; end |
722 end | 707 if config.urlBase ~= nil and type(config.urlBase) then urlBase = config.urlBase; end |
723 if config.showJoin == nil then | |
724 config.showJoin = true; | |
725 end | |
726 | 708 |
727 theme = config.theme or "prosody"; | 709 theme = config.theme or "prosody"; |
728 local themePath = themesParent .. "/" .. tostring(theme); | 710 local themePath = themesParent .. "/" .. tostring(theme); |
729 local attributes, err = lfs.attributes(themePath); | 711 local attributes, err = lfs.attributes(themePath); |
730 if attributes == nil or attributes.mode ~= "directory" then | 712 if attributes == nil or attributes.mode ~= "directory" then |
737 module:log("error", "Theme \"%s\" is missing something: %s", tostring(theme), err); | 719 module:log("error", "Theme \"%s\" is missing something: %s", tostring(theme), err); |
738 return false; | 720 return false; |
739 end | 721 end |
740 | 722 |
741 module:provides("http", { | 723 module:provides("http", { |
742 name = "muc_log"; | 724 default_path = urlBase, |
743 route = { | 725 route = { |
744 ["GET"] = function(event) | 726 ["GET /*"] = handle_request; |
745 event.response.headers.location = event.request.path .. "/"; | 727 } |
746 return 301; | |
747 end; | |
748 ["GET /*"] = handle_request; | |
749 } | |
750 }); | 728 }); |
751 end | 729 end |