changeset 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 84caab2bc02c
children 8d4f3cd41f82
files mod_admin_web/admin_web/mod_admin_web.lua mod_admin_web/admin_web/www_files/index.html mod_admin_web/admin_web/www_files/js/main.js mod_admin_web/admin_web/www_files/style.css
diffstat 4 files changed, 249 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/mod_admin_web/admin_web/mod_admin_web.lua	Wed Jan 19 20:18:38 2011 +0100
+++ b/mod_admin_web/admin_web/mod_admin_web.lua	Fri Jan 21 04:10:40 2011 +0100
@@ -25,8 +25,9 @@
 local open = io.open;
 local stat = lfs.attributes;
 
-local host = module:get_host();
-local service;
+module:set_global();
+
+local service = {};
 
 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files";
 
@@ -48,7 +49,7 @@
 
 local idmap = {};
 
-function add_client(session)
+function add_client(session, host)
 	local name = session.full_jid;
 	local id = idmap[name];
 	if not id then
@@ -62,20 +63,20 @@
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	service:publish(xmlns_c2s_session, host, id, item);
+	service[host]:publish(xmlns_c2s_session, host, id, item);
 	module:log("debug", "Added client " .. name);
 end
 
-function del_client(session)
+function del_client(session, host)
 	local name = session.full_jid;
 	local id = idmap[name];
 	if id then
 		local notifier = st.stanza("retract", { id = id });
-		service:retract(xmlns_c2s_session, host, id, notifier);
+		service[host]:retract(xmlns_c2s_session, host, id, notifier);
 	end
 end
 
-function add_host(session, type)
+function add_host(session, type, host)
 	local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
 	local id = idmap[name.."_"..type];
 	if not id then
@@ -90,16 +91,16 @@
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	service:publish(xmlns_s2s_session, host, id, item);
+	service[host]:publish(xmlns_s2s_session, host, id, item);
 	module:log("debug", "Added host " .. name .. " s2s" .. type);
 end
 
-function del_host(session, type)
+function del_host(session, type, host)
 	local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
 	local id = idmap[name.."_"..type];
 	if id then
 		local notifier = st.stanza("retract", { id = id });
-		service:retract(xmlns_s2s_session, host, id, notifier);
+		service[host]:retract(xmlns_s2s_session, host, id, notifier);
 	end
 end
 
@@ -137,7 +138,6 @@
 	local f, err = open(full_path, "rb");
 	if not f then return response_404; end
 	local data = f:read("*a");
-	data = data:gsub("%%ADMINSUBHOST%%", host);
 	f:close();
 	if not data then
 		return response_403;
@@ -164,47 +164,183 @@
 end
 
 prosody.events.add_handler("server-started", function ()
-	local host_session = prosody.hosts[host];
-	if not select(2, service:get_nodes(true))[xmlns_s2s_session] then
-		local ok, errmsg = service:create(xmlns_s2s_session, true);
-		if not ok then
-			module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
-		else
-			service:set_affiliation(xmlns_s2s_session, true, host, "owner")
+	for host_name, host_table in pairs(hosts) do
+		service[host_name] = pubsub.new({
+			broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end;
+			normalize_jid = jid_bare;
+			get_affiliation = function(jid) return get_affiliation(jid, host_name) end;
+			capabilities = {
+				member = {
+					create = false;
+					publish = false;
+					retract = false;
+					get_nodes = true;
+
+					subscribe = true;
+					unsubscribe = true;
+					get_subscription = true;
+					get_subscriptions = true;
+					get_items = true;
+
+					subscribe_other = false;
+					unsubscribe_other = false;
+					get_subscription_other = false;
+					get_subscriptions_other = false;
+
+					be_subscribed = true;
+					be_unsubscribed = true;
+
+					set_affiliation = false;
+				};
+
+				owner = {
+					create = true;
+					publish = true;
+					retract = true;
+					get_nodes = true;
+
+					subscribe = true;
+					unsubscribe = true;
+					get_subscription = true;
+					get_subscriptions = true;
+					get_items = true;
+
+					subscribe_other = true;
+					unsubscribe_other = true;
+					get_subscription_other = true;
+					get_subscriptions_other = true;
+
+					be_subscribed = true;
+					be_unsubscribed = true;
+
+					set_affiliation = true;
+				};
+			};
+		});
+
+		if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then
+			local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true);
+			if not ok then
+				module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
+			else
+				service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner")
+			end
 		end
-	end
 
-	for remotehost, session in pairs(host_session.s2sout) do
-		if session.type ~= "s2sout_unauthed" then
-			add_host(session, "out");
+		for remotehost, session in pairs(host_table.s2sout) do
+			if session.type ~= "s2sout_unauthed" then
+				add_host(session, "out", host_name);
+			end
+		end
+		for session in pairs(incoming_s2s) do
+			if session.to_host == host_name then
+				add_host(session, "in", host_name);
+			end
+		end
+
+		if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then
+			local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true);
+			if not ok then
+				module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
+			else
+				service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner")
+			end
 		end
-	end
-	for session in pairs(incoming_s2s) do
-		if session.to_host == host then
-			add_host(session, "in");
+
+		for username, user in pairs(host_table.sessions or {}) do
+			for resource, session in pairs(user.sessions or {}) do
+				add_client(session, host_name);
+			end
 		end
-	end
+
+		host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event)
+			local origin, stanza = event.origin, event.stanza;
+			local adminsub = stanza.tags[1];
+			local action = adminsub.tags[1];
+			local reply;
+			if action.name == "subscribe" then
+				local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+				if ok then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub });
+				else
+					reply = st.error_reply(stanza, "cancel", ret);
+				end
+			elseif action.name == "unsubscribe" then
+				local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+				if ok then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub });
+				else
+					reply = st.error_reply(stanza, "cancel", ret);
+				end
+			elseif action.name == "items" then
+				local node = action.attr.node;
+				local ok, ret = service[host_name]:get_items(node, stanza.attr.from);
+				if not ok then
+					return origin.send(st.error_reply(stanza, "cancel", ret));
+				end
 
-	if not select(2, service:get_nodes(true))[xmlns_c2s_session] then
-		local ok, errmsg = service:create(xmlns_c2s_session, true);
-		if not ok then
-			module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
-		else
-			service:set_affiliation(xmlns_c2s_session, true, host, "owner")
-		end
-	end
+				local data = st.stanza("items", { node = node });
+				for _, entry in pairs(ret) do
+					data:add_child(entry);
+				end
+				if data then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub })
+							:add_child(data);
+				else
+					reply = st.error_reply(stanza, "cancel", "item-not-found");
+				end
+			elseif action.name == "adminfor" then
+				local data = st.stanza("adminfor");
+				for host_name in pairs(hosts) do
+					if is_admin(stanza.attr.from, host_name) then
+						data:tag("item"):text(host_name):up();
+					end
+				end
+				reply = st.reply(stanza)
+					:tag("adminsub", { xmlns = xmlns_adminsub })
+						:add_child(data);
+			else
+				reply = st.error_reply(stanza, "feature-not-implemented");
+			end
+			return origin.send(reply);
+		end);
 
-	for username, user in pairs(host_session.sessions or {}) do
-		for resource, session in pairs(user.sessions or {}) do
-			add_client(session);
-		end
+		host_table.events.add_handler("resource-bind", function(event)
+			add_client(event.session, host_name);
+		end);
+
+		host_table.events.add_handler("resource-unbind", function(event)
+			del_client(event.session, host_name);
+			service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid);
+			service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid);
+		end);
+
+		host_table.events.add_handler("s2sout-established", function(event)
+			add_host(event.session, "out", host_name);
+		end);
+
+		host_table.events.add_handler("s2sin-established", function(event)
+			add_host(event.session, "in", host_name);
+		end);
+
+		host_table.events.add_handler("s2sout-destroyed", function(event)
+			del_host(event.session, "out", host_name);
+		end);
+
+		host_table.events.add_handler("s2sin-destroyed", function(event)
+			del_host(event.session, "in", host_name);
+		end);
+
 	end
 end);
 
-function simple_broadcast(node, jids, item)
+function simple_broadcast(node, jids, item, host)
 	item = st.clone(item);
 	item.attr.xmlns = nil; -- Clear the pubsub namespace
-	local message = st.message({ from = module.host, type = "headline" })
+	local message = st.message({ from = host, type = "headline" })
 		:tag("event", { xmlns = xmlns_adminsub .. "#event" })
 			:tag("items", { node = node })
 				:add_child(item);
@@ -215,7 +351,7 @@
 	end
 end
 
-function get_affiliation(jid)
+function get_affiliation(jid, host)
 	local bare_jid = jid_bare(jid);
 	if is_admin(bare_jid, host) then
 		return "member";
@@ -223,120 +359,3 @@
 		return "none";
 	end
 end
-
-module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event)
-	local origin, stanza = event.origin, event.stanza;
-	local adminsub = stanza.tags[1];
-	local action = adminsub.tags[1];
-	local reply;
-	if action.name == "subscribe" then
-		local ok, ret = service:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
-		if ok then
-			reply = st.reply(stanza)
-				:tag("adminsub", { xmlns = xmlns_adminsub });
-		else
-			reply = st.error_reply(stanza, "cancel", ret);
-		end
-	elseif action.name == "items" then
-		local node = action.attr.node;
-		local ok, ret = service:get_items(node, stanza.attr.from);
-		if not ok then
-			return origin.send(st.error_reply(stanza, "cancel", ret));
-		end
-
-		local data = st.stanza("items", { node = node });
-		for _, entry in pairs(ret) do
-			data:add_child(entry);
-		end
-		if data then
-			reply = st.reply(stanza)
-				:tag("adminsub", { xmlns = xmlns_adminsub })
-					:add_child(data);
-		else
-			reply = st.error_reply(stanza, "cancel", "item-not-found");
-		end
-	else
-		reply = st.error_reply(stanza, "feature-not-implemented");
-	end
-	return origin.send(reply);
-end);
-
-module:hook("resource-bind", function(event)
-	add_client(event.session);
-end);
-
-module:hook("resource-unbind", function(event)
-	del_client(event.session);
-	service:remove_subscription(xmlns_c2s_session, host, event.session.full_jid);
-	service:remove_subscription(xmlns_s2s_session, host, event.session.full_jid);
-end);
-
-module:hook("s2sout-established", function(event)
-	add_host(event.session, "out");
-end);
-
-module:hook("s2sin-established", function(event)
-	add_host(event.session, "in");
-end);
-
-module:hook("s2sout-destroyed", function(event)
-	del_host(event.session, "out");
-end);
-
-module:hook("s2sin-destroyed", function(event)
-	del_host(event.session, "in");
-end);
-
-service = pubsub.new({
-	broadcaster = simple_broadcast;
-	normalize_jid = jid_bare;
-	get_affiliation = get_affiliation;
-	capabilities = {
-		member = {
-			create = false;
-			publish = false;
-			retract = false;
-			get_nodes = true;
-
-			subscribe = true;
-			unsubscribe = true;
-			get_subscription = true;
-			get_subscriptions = true;
-			get_items = true;
-
-			subscribe_other = false;
-			unsubscribe_other = false;
-			get_subscription_other = false;
-			get_subscriptions_other = false;
-
-			be_subscribed = true;
-			be_unsubscribed = true;
-
-			set_affiliation = false;
-		};
-
-		owner = {
-			create = true;
-			publish = true;
-			retract = true;
-			get_nodes = true;
-
-			subscribe = true;
-			unsubscribe = true;
-			get_subscription = true;
-			get_subscriptions = true;
-			get_items = true;
-
-			subscribe_other = true;
-			unsubscribe_other = true;
-			get_subscription_other = true;
-			get_subscriptions_other = true;
-
-			be_subscribed = true;
-			be_unsubscribed = true;
-
-			set_affiliation = true;
-		};
-	};
-});
-
--- a/mod_admin_web/admin_web/www_files/index.html	Wed Jan 19 20:18:38 2011 +0100
+++ b/mod_admin_web/admin_web/www_files/index.html	Fri Jan 21 04:10:40 2011 +0100
@@ -36,6 +36,7 @@
 </div>
 
 <div id='main'>
+  <div id="selector">Host: <select id="host"></select></div>
   <div id="adhoc"></div>
   <div id="s2sList">
     <div class="container">
--- a/mod_admin_web/admin_web/www_files/js/main.js	Wed Jan 19 20:18:38 2011 +0100
+++ b/mod_admin_web/admin_web/www_files/js/main.js	Fri Jan 21 04:10:40 2011 +0100
@@ -1,5 +1,5 @@
 var BOSH_SERVICE = '/http-bind/';
-var show_log = true;
+var show_log = false;
 
 Strophe.addNamespace('C2SSTREAM', 'http://prosody.im/streams/c2s');
 Strophe.addNamespace('S2SSTREAM', 'http://prosody.im/streams/s2s');
@@ -9,7 +9,7 @@
 var localJID = null;
 var connection   = null;
 
-var adminsubHost = '%ADMINSUBHOST%';
+var adminsubHost = null;
 
 function log(msg) {
     var entry = $('<div></div>').append(document.createTextNode(msg));
@@ -105,17 +105,31 @@
         }
     } else if (status == Strophe.Status.CONNECTED) {
         log('Strophe is connected.');
-        showDisconnect();
-        connection.addHandler(_cbAdminSub, Strophe.NS.ADMINSUB + '#event', 'message');
-        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
-                .c('subscribe', {node: Strophe.NS.C2SSTREAM}));
-        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
-                .c('subscribe', {node: Strophe.NS.S2SSTREAM}));
-        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
-                .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S);
-        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
-                .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S);
-	Adhoc.checkFeatures('#adhoc', connection.domain);
+        connection.sendIQ($iq({to: connection.domain, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('adminfor'), function(e) {
+                var items;
+                items = e.getElementsByTagName('item');
+                if (items.length == 0) {
+                    alert("You are not an administrator");
+                    connection.disconnect();
+                    return false;
+                }
+                for (i = 0; i < items.length; i++) {
+                    $('#host').append('<option>' + $(items[i]).text() + '</option>');
+                }
+                showDisconnect();
+                adminsubHost = $(items[0]).text();
+                Adhoc.checkFeatures('#adhoc', adminsubHost);
+                connection.addHandler(_cbAdminSub, Strophe.NS.ADMINSUB + '#event', 'message');
+                connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                    .c('subscribe', {node: Strophe.NS.C2SSTREAM}));
+                connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                    .c('subscribe', {node: Strophe.NS.S2SSTREAM}));
+                connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                    .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S);
+                connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                    .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S);
+        });
     }
 }
 
@@ -128,14 +142,13 @@
     pass.show();
     jid.show();
     $('#menu').hide();
-    $('#adhoc').hide();
-    $('#s2sList').hide();
-    $('#c2sList').hide();
+    $('#main').hide();
     $('#cred label').show();
     $('#cred br').show();
     $('#s2sin').empty();
     $('#s2sout').empty();
     $('#c2s').empty();
+    $('#host').empty();
 }
 
 function showDisconnect() {
@@ -147,7 +160,10 @@
     pass.hide();
     jid.hide();
     $('#menu').show();
+    $('#main').show();
     $('#adhoc').show();
+    $('#s2sList').hide();
+    $('#c2sList').hide();
     $('#cred label').hide();
     $('#cred br').hide();
 }
@@ -172,9 +188,7 @@
 
         if (button.value == 'connect') {
             $('#log').empty();
-            connection.connect(localJID,
-               pass.get(0).value,
-               onConnect);
+            connection.connect(localJID, pass.get(0).value, onConnect);
         } else {
             connection.disconnect();
         }
@@ -182,26 +196,45 @@
     });
 
     $('#adhocMenu').click(function (event) {
-	$('#s2sList').slideUp();
-	$('#c2sList').slideUp();
-	$('#adhoc').slideDown();
+        $('#s2sList').slideUp();
+        $('#c2sList').slideUp();
+        $('#adhoc').slideDown();
         event.preventDefault();
     });
 
     $('#serverMenu').click(function (event) {
-	$('#adhoc').slideUp();
-	$('#c2sList').slideUp();
-	$('#s2sList').slideDown();
+        $('#adhoc').slideUp();
+        $('#c2sList').slideUp();
+        $('#s2sList').slideDown();
         event.preventDefault();
     });
 
     $('#clientMenu').click(function (event) {
-	$('#adhoc').slideUp();
-	$('#s2sList').slideUp();
-	$('#c2sList').slideDown();
+        $('#adhoc').slideUp();
+        $('#s2sList').slideUp();
+        $('#c2sList').slideDown();
         event.preventDefault();
     });
 
+    $('#host').bind('change', function (event) {
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('unsubscribe', {node: Strophe.NS.C2SSTREAM}));
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('unsubscribe', {node: Strophe.NS.S2SSTREAM}));
+        adminsubHost = $(this).val();
+        Adhoc.checkFeatures('#adhoc', adminsubHost);
+        $('#s2sin').empty();
+        $('#s2sout').empty();
+        $('#c2s').empty();
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('subscribe', {node: Strophe.NS.C2SSTREAM}));
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('subscribe', {node: Strophe.NS.S2SSTREAM}));
+        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S);
+        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+            .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S);
+    });
 });
 
 window.onunload = window.onbeforeunload = function() {
--- a/mod_admin_web/admin_web/www_files/style.css	Wed Jan 19 20:18:38 2011 +0100
+++ b/mod_admin_web/admin_web/www_files/style.css	Fri Jan 21 04:10:40 2011 +0100
@@ -33,11 +33,19 @@
   float: left;
   margin-right: 2em;
   padding: 1em;
+  border: solid 1px;
   background: #6197DF;
   color: #000000
 }
 
-#adhoc, #s2sList, #c2sList {
+#selector {
+  padding: 1em;
+  border: solid 1px;
+  background: #6197DF;
+  color: #000000
+}
+
+#main {
   display: none
 }