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 |
