X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=util%2Fpubsub.lua;h=d8ae1f38fa3f2993c66ceb50e83bacba0daf3eb0;hb=8f05e6d80fd64a095fe9bc7dc9825149c269439b;hp=bba0ed3a7fdacb2313c55b5a64503d63acbf50ab;hpb=166f7b6174251c684df3f30f6a3e4920c637d561;p=prosody.git diff --git a/util/pubsub.lua b/util/pubsub.lua index bba0ed3a..d8ae1f38 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -1,3 +1,5 @@ +local events = require "util.events"; + module("pubsub", package.seeall); local service = {}; @@ -14,7 +16,9 @@ function new(config) return setmetatable({ config = setmetatable(config, { __index = default_config }); affiliations = {}; + subscriptions = {}; nodes = {}; + events = events.new(); }, service_mt); end @@ -26,17 +30,14 @@ end function service:may(node, actor, action) if actor == true then return true; end - local node_obj = self.nodes[node]; local node_aff = node_obj and node_obj.affiliations[actor]; local service_aff = self.affiliations[actor] or self.config.get_affiliation(actor, node, action) or "none"; + -- Check if node allows/forbids it local node_capabilities = node_obj and node_obj.capabilities; - local service_capabilities = self.config.capabilities; - - -- Check if node allows/forbids it if node_capabilities then local caps = node_capabilities[node_aff or service_aff]; if caps then @@ -46,7 +47,9 @@ function service:may(node, actor, action) end end end + -- Check service-wide capabilities instead + local service_capabilities = self.config.capabilities; local caps = service_capabilities[node_aff or service_aff]; if caps then local can = caps[action]; @@ -69,14 +72,14 @@ function service:set_affiliation(node, actor, jid, affiliation) return false, "item-not-found"; end node_obj.affiliations[jid] = affiliation; - local _, jid_sub = self:get_subscription(node, nil, jid); + local _, jid_sub = self:get_subscription(node, true, jid); if not jid_sub and not self:may(node, jid, "be_unsubscribed") then - local ok, err = self:add_subscription(node, nil, jid); + local ok, err = self:add_subscription(node, true, jid); if not ok then return ok, err; end elseif jid_sub and not self:may(node, jid, "be_subscribed") then - local ok, err = self:add_subscription(node, nil, jid); + local ok, err = self:add_subscription(node, true, jid); if not ok then return ok, err; end @@ -87,7 +90,7 @@ end function service:add_subscription(node, actor, jid, options) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "subscribe"; else cap = "subscribe_other"; @@ -104,7 +107,7 @@ function service:add_subscription(node, actor, jid, options) if not self.config.autocreate_on_subscribe then return false, "item-not-found"; else - local ok, err = self:create(node, actor); + local ok, err = self:create(node, true); if not ok then return ok, err; end @@ -112,13 +115,25 @@ function service:add_subscription(node, actor, jid, options) end end node_obj.subscribers[jid] = options or true; + local normal_jid = self.config.normalize_jid(jid); + local subs = self.subscriptions[normal_jid]; + if subs then + if not subs[jid] then + subs[jid] = { [node] = true }; + else + subs[jid][node] = true; + end + else + self.subscriptions[normal_jid] = { [jid] = { [node] = true } }; + end + self.events.fire_event("subscription-added", { node = node, jid = jid, normalized_jid = normal_jid, options = options }); return true; end function service:remove_subscription(node, actor, jid) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "unsubscribe"; else cap = "unsubscribe_other"; @@ -138,13 +153,40 @@ function service:remove_subscription(node, actor, jid) return false, "not-subscribed"; end node_obj.subscribers[jid] = nil; + local normal_jid = self.config.normalize_jid(jid); + local subs = self.subscriptions[normal_jid]; + if subs then + local jid_subs = subs[jid]; + if jid_subs then + jid_subs[node] = nil; + if next(jid_subs) == nil then + subs[jid] = nil; + end + end + if next(subs) == nil then + self.subscriptions[normal_jid] = nil; + end + end + self.events.fire_event("subscription-removed", { node = node, jid = jid, normalized_jid = normal_jid }); + return true; +end + +function service:remove_all_subscriptions(actor, jid) + local normal_jid = self.config.normalize_jid(jid); + local subs = self.subscriptions[normal_jid] + subs = subs and subs[jid]; + if subs then + for node in pairs(subs) do + self:remove_subscription(node, true, jid); + end + end return true; end function service:get_subscription(node, actor, jid) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "get_subscription"; else cap = "get_subscription_other"; @@ -154,9 +196,10 @@ function service:get_subscription(node, actor, jid) end -- local node_obj = self.nodes[node]; - if node_obj then - return true, node_obj.subscribers[jid]; + if not node_obj then + return false, "item-not-found"; end + return true, node_obj.subscribers[jid]; end function service:create(node, actor) @@ -194,7 +237,7 @@ function service:publish(node, actor, id, item) if not self.config.autocreate_on_publish then return false, "item-not-found"; end - local ok, err = self:create(node, actor); + local ok, err = self:create(node, true); if not ok then return ok, err; end @@ -248,6 +291,55 @@ function service:get_nodes(actor) return true, self.nodes; end +function service:get_subscriptions(node, actor, jid) + -- Access checking + local cap; + if actor == true or jid == actor or self:jids_equal(actor, jid) then + cap = "get_subscriptions"; + else + cap = "get_subscriptions_other"; + end + if not self:may(node, actor, cap) then + return false, "forbidden"; + end + -- + local node_obj; + if node then + node_obj = self.nodes[node]; + if not node_obj then + return false, "item-not-found"; + end + end + local normal_jid = self.config.normalize_jid(jid); + local subs = self.subscriptions[normal_jid]; + -- We return the subscription object from the node to save + -- a get_subscription() call for each node. + local ret = {}; + if subs then + for jid, subscribed_nodes in pairs(subs) do + if node then -- Return only subscriptions to this node + if subscribed_nodes[node] then + ret[#ret+1] = { + node = subscribed_node; + jid = jid; + subscription = node_obj.subscribers[jid]; + }; + end + else -- Return subscriptions to all nodes + local nodes = self.nodes; + for subscribed_node in pairs(subscribed_nodes) do + ret[#ret+1] = { + node = subscribed_node; + jid = jid; + subscription = nodes[subscribed_node].subscribers[jid]; + }; + end + end + end + end + return true, ret; +end + -- Access models only affect 'none' affiliation caps, service/default access level... function service:set_node_capabilities(node, actor, capabilities) -- Access checking