1 local st = require "util.stanza"; |
|
2 local url = require"socket.url"; |
1 local url = require"socket.url"; |
|
2 local render = require"util.interpolation".new("%b{}", require"util.stanza".xml_escape); |
3 |
3 |
4 module:depends"http"; |
4 module:depends"http"; |
5 |
5 |
6 -- local dump = require"util.serialization".new"dump".serialize; |
|
7 |
|
8 local function template(data) |
|
9 --[[ DOC |
|
10 Like util.template, but deals with plain text |
|
11 Returns a closure that is called with a table of values |
|
12 {name} is substituted for values["name"] and is XML escaped |
|
13 {name!} is substituted without XML escaping |
|
14 {name?} is optional and is replaced with an empty string if no value exists |
|
15 ]] |
|
16 return function(values) |
|
17 return (data:gsub("{([^}]-)(%p?)}", function (name, opt) |
|
18 local value = values[name]; |
|
19 if value then |
|
20 if opt ~= "!" then |
|
21 return st.xml_escape(value); |
|
22 end |
|
23 return value; |
|
24 elseif opt == "?" then |
|
25 return ""; |
|
26 end |
|
27 end)); |
|
28 end |
|
29 end |
|
30 |
|
31 -- TODO Move templates into files |
6 -- TODO Move templates into files |
32 local base = template(template[[ |
7 local base_template = [[ |
33 <!DOCTYPE html> |
8 <!DOCTYPE html> |
34 <html> |
9 <html> |
35 <head> |
10 <head> |
36 <meta charset="utf-8"> |
11 <meta charset="utf-8"> |
37 <meta name="viewport" content="width=device-width, initial-scale=1"> |
12 <meta name="viewport" content="width=device-width, initial-scale=1"> |
69 </style> |
44 </style> |
70 </head> |
45 </head> |
71 <body> |
46 <body> |
72 <header> |
47 <header> |
73 <h1>{title}</h1> |
48 <h1>{title}</h1> |
74 {header!} |
|
75 </header> |
49 </header> |
76 <hr> |
50 <hr> |
77 <div class="content"> |
51 <div class="content"> |
78 {body!} |
52 <nav> |
|
53 <ul>{items# |
|
54 <li><a href="{item.url}" title="{item.module}">{item.name}</a></li>} |
|
55 </ul> |
|
56 </nav> |
79 </div> |
57 </div> |
80 <hr> |
58 <hr> |
81 <footer> |
59 <footer> |
82 {footer!} |
|
83 <br> |
60 <br> |
84 <div class="powered-by">Prosody {prosody_version?}</div> |
61 <div class="powered-by">Prosody {prosody_version?}</div> |
85 </footer> |
62 </footer> |
86 </body> |
63 </body> |
87 </html> |
64 </html> |
88 ]] { prosody_version = prosody.version, mod_name = module.name }); |
65 ]]; |
89 |
66 |
90 local canonical = module:http_url(nil, "/"); |
67 local canonical = module:http_url(nil, "/"); |
91 local page_template = template(base{ |
|
92 canonical = canonical; |
|
93 title = "HTTP stuff"; |
|
94 header = ""; |
|
95 body = [[ |
|
96 <nav> |
|
97 <ul> |
|
98 {lines!} |
|
99 </ul> |
|
100 </nav> |
|
101 ]]; |
|
102 footer = ""; |
|
103 }); |
|
104 local line_template = template[[ |
|
105 <li><a href="{url}" title="{module}">{name}</a></li> |
|
106 ]]; |
|
107 |
68 |
108 local function relative(base, link) |
69 local function relative(base, link) |
109 base = url.parse(base); |
70 base = url.parse(base); |
110 link = url.parse(link); |
71 link = url.parse(link); |
111 for k,v in pairs(base) do |
72 for k,v in pairs(base) do |
115 end |
76 end |
116 return url.build(link); |
77 return url.build(link); |
117 end |
78 end |
118 |
79 |
119 local function handler(event) |
80 local function handler(event) |
120 local items = module:get_host_items("http-provider"); |
81 local host_items = module:get_host_items("http-provider"); |
121 local item; |
82 local http_apps = {} |
122 for i = 1, #items do |
83 for _, item in ipairs(host_items) do |
123 item = items[i]; |
|
124 if module.name ~= item._provided_by then |
84 if module.name ~= item._provided_by then |
125 items[i] = line_template{ |
85 table.insert(http_apps, { |
126 name = item.name; |
86 name = item.name; |
127 module = "mod_" .. item._provided_by; |
87 module = "mod_" .. item._provided_by; |
128 url = relative(canonical, module:http_url(item.name, item.default_path)); |
88 url = relative(canonical, module:http_url(item.name, item.default_path)); |
129 }; |
89 }); |
130 else |
|
131 items[i] = ""; |
|
132 end |
90 end |
133 end |
91 end |
134 event.response.headers.content_type = "text/html"; |
92 event.response.headers.content_type = "text/html"; |
135 return page_template{ |
93 return render(base_template, { |
136 lines = table.concat(items); |
94 title = "HTTP Apps"; |
137 }; |
95 items = http_apps; |
|
96 prosody_version = prosody.version; |
|
97 mod_name = module.name; |
|
98 canonical = canonical; |
|
99 }); |
138 end |
100 end |
139 |
101 |
140 module:provides("http", { |
102 module:provides("http", { |
141 route = { |
103 route = { |
142 ["GET /"] = handler; |
104 ["GET /"] = handler; |