Mercurial > prosody-modules
comparison mod_http_muc_log/mod_http_muc_log.lua @ 1555:2e51f70cd7ea
mod_http_muc_log: Make pretty
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 09 Nov 2014 08:38:57 +0100 |
parents | 8059b7cdaf17 |
children | 0b80a02c2e3d |
comparison
equal
deleted
inserted
replaced
1554:8059b7cdaf17 | 1555:2e51f70cd7ea |
---|---|
27 end | 27 end |
28 | 28 |
29 module:depends"http"; | 29 module:depends"http"; |
30 | 30 |
31 local function template(data) | 31 local function template(data) |
32 local _doc = [[ | 32 --[[ DOC |
33 Like util.template, but deals with plain text | 33 Like util.template, but deals with plain text |
34 Returns a closure that is called with a table of values | 34 Returns a closure that is called with a table of values |
35 {name} is substituted for values["name"] and is XML escaped | 35 {name} is substituted for values["name"] and is XML escaped |
36 {name!} is substituted without XML escaping | 36 {name!} is substituted without XML escaping |
37 {name?} is optional and is replaced with an empty string if no value exists | 37 {name?} is optional and is replaced with an empty string if no value exists |
49 end | 49 end |
50 end)); | 50 end)); |
51 end | 51 end |
52 end | 52 end |
53 | 53 |
54 local base = template[[ | 54 -- TODO Move templates into files |
55 local base = template(template[[ | |
55 <!DOCTYPE html> | 56 <!DOCTYPE html> |
57 <html> | |
58 <head> | |
56 <meta charset="utf-8"> | 59 <meta charset="utf-8"> |
57 <title>{title}</title> | 60 <title>{title}</title> |
58 <style> | 61 <style> |
59 body { margin: 1ex 1em; } | 62 body{background-color:#eeeeec;margin:1ex 0;padding-bottom:3em;font-family:Arial,Helvetica,sans-serif;} |
60 ul { padding: 0; } | 63 header,footer{margin:1ex 1em;font-size:smaller;color:#babdb6;} |
61 li.action dt, li.action dd { display: inline-block; margin-left: 0;} | 64 .content{background-color:white;padding:1em;list-style-position:inside;} |
62 li.action dd { margin-left: 1ex;} | 65 nav{font-size:x-large;margin:1ex 2em;} |
63 li { list-style: none; } | 66 nav a{text-decoration:none;} |
64 li:hover { background: #eee; } | 67 nav a.up{font-size:smaller;} |
65 li time { float: right; font-size: small; opacity: 0.2; } | 68 nav a.next{float:right;} |
66 li:hover time { opacity: 1; } | 69 a:link,a:visited{color:#2e3436;text-decoration:none;} |
67 li.join , li.leave { color: green; } | 70 a:link:hover,a:visited:hover{color:#3465a4;} |
68 li.join dt, li.leave dt { color: green; } | 71 ul,ol{padding:0;} |
69 nav { font-size: x-large; margin: 1ex 2em; } | 72 li{list-style:none;} |
70 nav a { text-decoration: none; } | 73 hr{display:none;} |
74 li time{float:right;font-size:small;opacity:0.2;} | |
75 li:hover time{opacity:1;} | |
76 .room-list .name{font-size:larger;} | |
77 q.body::before,q.body::after{content:"";} | |
78 .presence .verb{font-style:normal;color:#30c030;} | |
79 .presence.unavailable .verb{color:#c03030;} | |
71 </style> | 80 </style> |
81 </head> | |
82 <body> | |
72 <h1>{title}</h1> | 83 <h1>{title}</h1> |
84 <header> | |
85 {header!} | |
86 </header> | |
87 <hr> | |
88 <div class="content"> | |
73 {body!} | 89 {body!} |
74 ]] | 90 </div> |
91 <hr> | |
92 <footer> | |
93 {footer!} | |
94 <div class="powered-by">Prosody {prosody_version?}</div> | |
95 </footer> | |
96 </head> | |
97 </html> | |
98 ]] { prosody_version = prosody.version }); | |
75 | 99 |
76 local dates_template = template(base{ | 100 local dates_template = template(base{ |
77 title = "Logs for room {room}"; | 101 title = "Logs for room {room}"; |
102 header = [[ | |
103 <nav> | |
104 <a href=".." class="up">Back to room list</a> | |
105 </nav> | |
106 ]]; | |
78 body = [[ | 107 body = [[ |
79 <base href="{room}/"> | |
80 <nav> | 108 <nav> |
81 <a href="..">↑</a> | 109 <ul class="dates"> |
110 {lines!}</ul> | |
82 </nav> | 111 </nav> |
83 <ul> | 112 ]]; |
84 {lines!}</ul> | 113 footer = ""; |
85 ]]; | |
86 }) | 114 }) |
87 | 115 |
88 local date_line_template = template[[ | 116 local date_line_template = template[[ |
89 <li><a href="{date}">{date}</a></li> | 117 <li><a href="{date}">{date}</a></li> |
90 ]]; | 118 ]]; |
91 | 119 |
92 local page_template = template(base{ | 120 local page_template = template(base{ |
93 title = "Logs for room {room} on {date}"; | 121 title = "Logs for room {room} on {date}"; |
122 header = [[ | |
123 <nav> | |
124 <a class="up" href=".">Back to date list</a> | |
125 <br> | |
126 <a class="prev" href="{prev}">← {prev}</a> | |
127 <a class="next" href="{next}">{next} →</a> | |
128 </nav> | |
129 ]]; | |
94 body = [[ | 130 body = [[ |
131 <ol class="chat-logs"> | |
132 {logs!}</ol> | |
133 ]]; | |
134 footer = [[ | |
95 <nav> | 135 <nav> |
96 <a class="prev" href="{prev}">←</a> | 136 <div> |
97 <a class="up" href=".">↑</a> | 137 <a class="prev" href="{prev}">← {prev}</a> |
98 <a class="next" href="{next}">→</a> | 138 <a class="next" href="{next}">{next} →</a> |
139 </div> | |
99 </nav> | 140 </nav> |
100 <ul> | 141 <script> |
101 {logs!} | 142 (function () { |
102 </ul> | 143 var timeTags = document.getElementsByTagName("time"); |
144 var i = 0; | |
145 var date; | |
146 while(timeTags[i]) { | |
147 date = new Date(timeTags[i].getAttribute("datetime")); | |
148 timeTags[i].textContent = date.toLocaleTimeString(); | |
149 timeTags[i].setAttribute("title", date.toString()); | |
150 i++; | |
151 } | |
152 })(); | |
153 </script> | |
103 ]]; | 154 ]]; |
104 }); | 155 }); |
105 | 156 |
106 local line_templates = { | 157 local line_template = template[[ |
107 ["message<groupchat"] = template[[ | 158 <li class="{st_name} {st_type?}" id="{key}"> |
108 <li id="{key}" class="{st_name}"><a href="#{key}"><time>{time}</time></a><dl><dt>{nick}</dt><dd>{body}</dd></dl></li> | 159 <span class="time"> |
109 ]]; | 160 <a href="#{key}"><time datetime="{datetime}">{time}</time></a> |
110 ["message<groupchat<subject"] = template[[ | 161 </span> |
111 <li id="{key}" class="{st_name} action subject"><a href="#{key}"><time>{time}</time></a><dl><dt>{nick}</dt><dd>changed subject to {subject}</dd></dl></li> | 162 <b class="nick">{nick}</b> |
112 ]]; | 163 <em class="verb">{verb?}</em> |
113 ["presence"] = template[[ | 164 <q class="body">{body?}</q> |
114 <li id="{key}" class="action join"><a href="#{key}"><time>{time}</time></a><dl><dt>{nick}</dt><dd>joined</dd></dl></li> | 165 </li> |
115 ]]; | 166 ]]; |
116 ["presence<unavailable"] = template[[ | |
117 <li id="{key}" class="action leave"><a href="#{key}"><time>{time}</time></a><dl><dt>{nick}</dt><dd>left</dd></dl></li> | |
118 ]]; | |
119 }; | |
120 | 167 |
121 local room_list_template = template(base{ | 168 local room_list_template = template(base{ |
122 title = "Rooms on {host}"; | 169 title = "Rooms on {host}"; |
170 header = ""; | |
123 body = [[ | 171 body = [[ |
124 <dl> | 172 <dl class="room-list"> |
125 {rooms!} | 173 {rooms!} |
126 </dl> | 174 </dl> |
127 ]]; | 175 ]]; |
176 footer = ""; | |
128 }); | 177 }); |
129 | 178 |
130 local room_item_template = template[[ | 179 local room_item_template = template[[ |
131 <dt><a href="{room}/">{name}</a></dt> | 180 <dt class="name"><a href="{room}/">{name}</a></dt> |
132 <dd>{description?}</dd> | 181 <dd class="description">{description?}</dd> |
133 ]]; | 182 ]]; |
134 | 183 |
135 local function public_room(room) | 184 local function public_room(room) |
136 if type(room) == "string" then | 185 if type(room) == "string" then |
137 room = get_room(room); | 186 room = get_room(room); |
190 limit = math.huge; | 239 limit = math.huge; |
191 -- with = "message<groupchat"; | 240 -- with = "message<groupchat"; |
192 }); | 241 }); |
193 if not iter then return 500; end | 242 if not iter then return 500; end |
194 | 243 |
195 local templ, typ; | 244 local verb, subject, body; |
196 for key, message, when in iter do | 245 for key, item, when in iter do |
197 templ = message.name; | 246 body = item:get_child_text("body"); |
198 local typ = message.attr.type; | 247 subject = item:get_child_text("subject"); |
199 if typ then templ = templ .. '<' .. typ; end | 248 verb = nil; |
200 local subject = message:get_child_text("subject"); | 249 if subject then |
201 if subject then templ = templ .. '<subject'; end | 250 verb = "set the topic to"; |
202 templ = line_templates[templ]; | 251 elseif body and body:sub(1,4) == "/me " then |
203 if templ then | 252 verb, body = body:sub(5), nil; |
204 logs[i], i = templ { | 253 elseif item.name == "presence" then |
205 key = key; | 254 verb = item.attr.type == "unavailable" and "has left" or "has joined"; |
206 time = datetime.time(when); | 255 end |
207 nick = select(3, jid_split(message.attr.from)); | 256 logs[i], i = line_template { |
208 body = message:get_child_text("body"); | 257 key = key; |
209 subject = subject; | 258 datetime = datetime.datetime(when); |
210 st_name = message.name; | 259 time = datetime.time(when); |
211 st_type = message.attr.type; | 260 verb = verb; |
212 }, i + 1; | 261 body = subject or body; |
213 else | 262 nick = select(3, jid_split(item.attr.from)); |
214 module:log("debug", "No template for %s", tostring(message)); | 263 st_name = item.name; |
215 end | 264 st_type = item.attr.type; |
265 }, i + 1; | |
216 end | 266 end |
217 | 267 |
218 local next_when = datetime.parse(date.."T12:00:00Z") + 86400; | 268 local next_when = datetime.parse(date.."T12:00:00Z") + 86400; |
219 local prev_when = datetime.parse(date.."T12:00:00Z") - 86400; | 269 local prev_when = datetime.parse(date.."T12:00:00Z") - 86400; |
220 | 270 |