comparison mod_admin_web/admin_web/mod_admin_web.lua @ 319:ba2e78661ea8

mod_admin_web: Make module global. Host to administrate is now chooseable
author Florian Zeitz <florob@babelmonkeys.de>
date Fri, 21 Jan 2011 04:10:40 +0100
parents 4f78f5020aa9
children 73001ddff453
comparison
equal deleted inserted replaced
318:84caab2bc02c 319:ba2e78661ea8
23 local jid_bare = require "util.jid".bare; 23 local jid_bare = require "util.jid".bare;
24 local lfs = require "lfs"; 24 local lfs = require "lfs";
25 local open = io.open; 25 local open = io.open;
26 local stat = lfs.attributes; 26 local stat = lfs.attributes;
27 27
28 local host = module:get_host(); 28 module:set_global();
29 local service; 29
30 local service = {};
30 31
31 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files"; 32 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files";
32 33
33 local xmlns_adminsub = "http://prosody.im/adminsub"; 34 local xmlns_adminsub = "http://prosody.im/adminsub";
34 local xmlns_c2s_session = "http://prosody.im/streams/c2s"; 35 local xmlns_c2s_session = "http://prosody.im/streams/c2s";
46 css = "text/css"; 47 css = "text/css";
47 }; 48 };
48 49
49 local idmap = {}; 50 local idmap = {};
50 51
51 function add_client(session) 52 function add_client(session, host)
52 local name = session.full_jid; 53 local name = session.full_jid;
53 local id = idmap[name]; 54 local id = idmap[name];
54 if not id then 55 if not id then
55 id = uuid_generate(); 56 id = uuid_generate();
56 idmap[name] = id; 57 idmap[name] = id;
60 item:tag("encrypted"):up(); 61 item:tag("encrypted"):up();
61 end 62 end
62 if session.compressed then 63 if session.compressed then
63 item:tag("compressed"):up(); 64 item:tag("compressed"):up();
64 end 65 end
65 service:publish(xmlns_c2s_session, host, id, item); 66 service[host]:publish(xmlns_c2s_session, host, id, item);
66 module:log("debug", "Added client " .. name); 67 module:log("debug", "Added client " .. name);
67 end 68 end
68 69
69 function del_client(session) 70 function del_client(session, host)
70 local name = session.full_jid; 71 local name = session.full_jid;
71 local id = idmap[name]; 72 local id = idmap[name];
72 if id then 73 if id then
73 local notifier = st.stanza("retract", { id = id }); 74 local notifier = st.stanza("retract", { id = id });
74 service:retract(xmlns_c2s_session, host, id, notifier); 75 service[host]:retract(xmlns_c2s_session, host, id, notifier);
75 end 76 end
76 end 77 end
77 78
78 function add_host(session, type) 79 function add_host(session, type, host)
79 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); 80 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
80 local id = idmap[name.."_"..type]; 81 local id = idmap[name.."_"..type];
81 if not id then 82 if not id then
82 id = uuid_generate(); 83 id = uuid_generate();
83 idmap[name.."_"..type] = id; 84 idmap[name.."_"..type] = id;
88 item:tag("encrypted"):up(); 89 item:tag("encrypted"):up();
89 end 90 end
90 if session.compressed then 91 if session.compressed then
91 item:tag("compressed"):up(); 92 item:tag("compressed"):up();
92 end 93 end
93 service:publish(xmlns_s2s_session, host, id, item); 94 service[host]:publish(xmlns_s2s_session, host, id, item);
94 module:log("debug", "Added host " .. name .. " s2s" .. type); 95 module:log("debug", "Added host " .. name .. " s2s" .. type);
95 end 96 end
96 97
97 function del_host(session, type) 98 function del_host(session, type, host)
98 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); 99 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
99 local id = idmap[name.."_"..type]; 100 local id = idmap[name.."_"..type];
100 if id then 101 if id then
101 local notifier = st.stanza("retract", { id = id }); 102 local notifier = st.stanza("retract", { id = id });
102 service:retract(xmlns_s2s_session, host, id, notifier); 103 service[host]:retract(xmlns_s2s_session, host, id, notifier);
103 end 104 end
104 end 105 end
105 106
106 local function preprocess_path(path) 107 local function preprocess_path(path)
107 if path:sub(1,1) ~= "/" then 108 if path:sub(1,1) ~= "/" then
135 return response_403; 136 return response_403;
136 end 137 end
137 local f, err = open(full_path, "rb"); 138 local f, err = open(full_path, "rb");
138 if not f then return response_404; end 139 if not f then return response_404; end
139 local data = f:read("*a"); 140 local data = f:read("*a");
140 data = data:gsub("%%ADMINSUBHOST%%", host);
141 f:close(); 141 f:close();
142 if not data then 142 if not data then
143 return response_403; 143 return response_403;
144 end 144 end
145 local ext = path:match("%.([^.]*)$"); 145 local ext = path:match("%.([^.]*)$");
162 162
163 httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" }); 163 httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" });
164 end 164 end
165 165
166 prosody.events.add_handler("server-started", function () 166 prosody.events.add_handler("server-started", function ()
167 local host_session = prosody.hosts[host]; 167 for host_name, host_table in pairs(hosts) do
168 if not select(2, service:get_nodes(true))[xmlns_s2s_session] then 168 service[host_name] = pubsub.new({
169 local ok, errmsg = service:create(xmlns_s2s_session, true); 169 broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end;
170 if not ok then 170 normalize_jid = jid_bare;
171 module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg)); 171 get_affiliation = function(jid) return get_affiliation(jid, host_name) end;
172 else 172 capabilities = {
173 service:set_affiliation(xmlns_s2s_session, true, host, "owner") 173 member = {
174 end 174 create = false;
175 end 175 publish = false;
176 176 retract = false;
177 for remotehost, session in pairs(host_session.s2sout) do 177 get_nodes = true;
178 if session.type ~= "s2sout_unauthed" then 178
179 add_host(session, "out"); 179 subscribe = true;
180 end 180 unsubscribe = true;
181 end 181 get_subscription = true;
182 for session in pairs(incoming_s2s) do 182 get_subscriptions = true;
183 if session.to_host == host then 183 get_items = true;
184 add_host(session, "in"); 184
185 end 185 subscribe_other = false;
186 end 186 unsubscribe_other = false;
187 187 get_subscription_other = false;
188 if not select(2, service:get_nodes(true))[xmlns_c2s_session] then 188 get_subscriptions_other = false;
189 local ok, errmsg = service:create(xmlns_c2s_session, true); 189
190 if not ok then 190 be_subscribed = true;
191 module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg)); 191 be_unsubscribed = true;
192 else 192
193 service:set_affiliation(xmlns_c2s_session, true, host, "owner") 193 set_affiliation = false;
194 end 194 };
195 end 195
196 196 owner = {
197 for username, user in pairs(host_session.sessions or {}) do 197 create = true;
198 for resource, session in pairs(user.sessions or {}) do 198 publish = true;
199 add_client(session); 199 retract = true;
200 end 200 get_nodes = true;
201
202 subscribe = true;
203 unsubscribe = true;
204 get_subscription = true;
205 get_subscriptions = true;
206 get_items = true;
207
208 subscribe_other = true;
209 unsubscribe_other = true;
210 get_subscription_other = true;
211 get_subscriptions_other = true;
212
213 be_subscribed = true;
214 be_unsubscribed = true;
215
216 set_affiliation = true;
217 };
218 };
219 });
220
221 if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then
222 local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true);
223 if not ok then
224 module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
225 else
226 service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner")
227 end
228 end
229
230 for remotehost, session in pairs(host_table.s2sout) do
231 if session.type ~= "s2sout_unauthed" then
232 add_host(session, "out", host_name);
233 end
234 end
235 for session in pairs(incoming_s2s) do
236 if session.to_host == host_name then
237 add_host(session, "in", host_name);
238 end
239 end
240
241 if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then
242 local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true);
243 if not ok then
244 module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
245 else
246 service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner")
247 end
248 end
249
250 for username, user in pairs(host_table.sessions or {}) do
251 for resource, session in pairs(user.sessions or {}) do
252 add_client(session, host_name);
253 end
254 end
255
256 host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event)
257 local origin, stanza = event.origin, event.stanza;
258 local adminsub = stanza.tags[1];
259 local action = adminsub.tags[1];
260 local reply;
261 if action.name == "subscribe" then
262 local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
263 if ok then
264 reply = st.reply(stanza)
265 :tag("adminsub", { xmlns = xmlns_adminsub });
266 else
267 reply = st.error_reply(stanza, "cancel", ret);
268 end
269 elseif action.name == "unsubscribe" then
270 local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
271 if ok then
272 reply = st.reply(stanza)
273 :tag("adminsub", { xmlns = xmlns_adminsub });
274 else
275 reply = st.error_reply(stanza, "cancel", ret);
276 end
277 elseif action.name == "items" then
278 local node = action.attr.node;
279 local ok, ret = service[host_name]:get_items(node, stanza.attr.from);
280 if not ok then
281 return origin.send(st.error_reply(stanza, "cancel", ret));
282 end
283
284 local data = st.stanza("items", { node = node });
285 for _, entry in pairs(ret) do
286 data:add_child(entry);
287 end
288 if data then
289 reply = st.reply(stanza)
290 :tag("adminsub", { xmlns = xmlns_adminsub })
291 :add_child(data);
292 else
293 reply = st.error_reply(stanza, "cancel", "item-not-found");
294 end
295 elseif action.name == "adminfor" then
296 local data = st.stanza("adminfor");
297 for host_name in pairs(hosts) do
298 if is_admin(stanza.attr.from, host_name) then
299 data:tag("item"):text(host_name):up();
300 end
301 end
302 reply = st.reply(stanza)
303 :tag("adminsub", { xmlns = xmlns_adminsub })
304 :add_child(data);
305 else
306 reply = st.error_reply(stanza, "feature-not-implemented");
307 end
308 return origin.send(reply);
309 end);
310
311 host_table.events.add_handler("resource-bind", function(event)
312 add_client(event.session, host_name);
313 end);
314
315 host_table.events.add_handler("resource-unbind", function(event)
316 del_client(event.session, host_name);
317 service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid);
318 service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid);
319 end);
320
321 host_table.events.add_handler("s2sout-established", function(event)
322 add_host(event.session, "out", host_name);
323 end);
324
325 host_table.events.add_handler("s2sin-established", function(event)
326 add_host(event.session, "in", host_name);
327 end);
328
329 host_table.events.add_handler("s2sout-destroyed", function(event)
330 del_host(event.session, "out", host_name);
331 end);
332
333 host_table.events.add_handler("s2sin-destroyed", function(event)
334 del_host(event.session, "in", host_name);
335 end);
336
201 end 337 end
202 end); 338 end);
203 339
204 function simple_broadcast(node, jids, item) 340 function simple_broadcast(node, jids, item, host)
205 item = st.clone(item); 341 item = st.clone(item);
206 item.attr.xmlns = nil; -- Clear the pubsub namespace 342 item.attr.xmlns = nil; -- Clear the pubsub namespace
207 local message = st.message({ from = module.host, type = "headline" }) 343 local message = st.message({ from = host, type = "headline" })
208 :tag("event", { xmlns = xmlns_adminsub .. "#event" }) 344 :tag("event", { xmlns = xmlns_adminsub .. "#event" })
209 :tag("items", { node = node }) 345 :tag("items", { node = node })
210 :add_child(item); 346 :add_child(item);
211 for jid in pairs(jids) do 347 for jid in pairs(jids) do
212 module:log("debug", "Sending notification to %s", jid); 348 module:log("debug", "Sending notification to %s", jid);
213 message.attr.to = jid; 349 message.attr.to = jid;
214 core_post_stanza(hosts[host], message); 350 core_post_stanza(hosts[host], message);
215 end 351 end
216 end 352 end
217 353
218 function get_affiliation(jid) 354 function get_affiliation(jid, host)
219 local bare_jid = jid_bare(jid); 355 local bare_jid = jid_bare(jid);
220 if is_admin(bare_jid, host) then 356 if is_admin(bare_jid, host) then
221 return "member"; 357 return "member";
222 else 358 else
223 return "none"; 359 return "none";
224 end 360 end
225 end 361 end
226
227 module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event)
228 local origin, stanza = event.origin, event.stanza;
229 local adminsub = stanza.tags[1];
230 local action = adminsub.tags[1];
231 local reply;
232 if action.name == "subscribe" then
233 local ok, ret = service:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
234 if ok then
235 reply = st.reply(stanza)
236 :tag("adminsub", { xmlns = xmlns_adminsub });
237 else
238 reply = st.error_reply(stanza, "cancel", ret);
239 end
240 elseif action.name == "items" then
241 local node = action.attr.node;
242 local ok, ret = service:get_items(node, stanza.attr.from);
243 if not ok then
244 return origin.send(st.error_reply(stanza, "cancel", ret));
245 end
246
247 local data = st.stanza("items", { node = node });
248 for _, entry in pairs(ret) do
249 data:add_child(entry);
250 end
251 if data then
252 reply = st.reply(stanza)
253 :tag("adminsub", { xmlns = xmlns_adminsub })
254 :add_child(data);
255 else
256 reply = st.error_reply(stanza, "cancel", "item-not-found");
257 end
258 else
259 reply = st.error_reply(stanza, "feature-not-implemented");
260 end
261 return origin.send(reply);
262 end);
263
264 module:hook("resource-bind", function(event)
265 add_client(event.session);
266 end);
267
268 module:hook("resource-unbind", function(event)
269 del_client(event.session);
270 service:remove_subscription(xmlns_c2s_session, host, event.session.full_jid);
271 service:remove_subscription(xmlns_s2s_session, host, event.session.full_jid);
272 end);
273
274 module:hook("s2sout-established", function(event)
275 add_host(event.session, "out");
276 end);
277
278 module:hook("s2sin-established", function(event)
279 add_host(event.session, "in");
280 end);
281
282 module:hook("s2sout-destroyed", function(event)
283 del_host(event.session, "out");
284 end);
285
286 module:hook("s2sin-destroyed", function(event)
287 del_host(event.session, "in");
288 end);
289
290 service = pubsub.new({
291 broadcaster = simple_broadcast;
292 normalize_jid = jid_bare;
293 get_affiliation = get_affiliation;
294 capabilities = {
295 member = {
296 create = false;
297 publish = false;
298 retract = false;
299 get_nodes = true;
300
301 subscribe = true;
302 unsubscribe = true;
303 get_subscription = true;
304 get_subscriptions = true;
305 get_items = true;
306
307 subscribe_other = false;
308 unsubscribe_other = false;
309 get_subscription_other = false;
310 get_subscriptions_other = false;
311
312 be_subscribed = true;
313 be_unsubscribed = true;
314
315 set_affiliation = false;
316 };
317
318 owner = {
319 create = true;
320 publish = true;
321 retract = true;
322 get_nodes = true;
323
324 subscribe = true;
325 unsubscribe = true;
326 get_subscription = true;
327 get_subscriptions = true;
328 get_items = true;
329
330 subscribe_other = true;
331 unsubscribe_other = true;
332 get_subscription_other = true;
333 get_subscriptions_other = true;
334
335 be_subscribed = true;
336 be_unsubscribed = true;
337
338 set_affiliation = true;
339 };
340 };
341 });
342