return setmetatable({
config = setmetatable(config, { __index = default_config });
affiliations = {};
+ subscriptions = {};
nodes = {};
}, service_mt);
end
+function service:jids_equal(jid1, jid2)
+ local normalize = self.config.normalize_jid;
+ return normalize(jid1) == normalize(jid2);
+end
+
function service:may(node, actor, action)
if actor == true then return true; end
function service:add_subscription(node, actor, jid, options)
-- Access checking
local cap;
- if jid == actor or self.config.jids_equal(actor, jid) then
+ if jid == actor or self:jids_equal(actor, jid) then
cap = "subscribe";
else
cap = "subscribe_other";
if not ok then
return ok, err;
end
+ node_obj = self.nodes[node];
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
return true;
end
function service:remove_subscription(node, actor, jid)
-- Access checking
local cap;
- if jid == actor or self.config.jids_equal(actor, jid) then
+ if jid == actor or self:jids_equal(actor, jid) then
cap = "unsubscribe";
else
cap = "unsubscribe_other";
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
return true;
end
function service:get_subscription(node, actor, jid)
-- Access checking
local cap;
- if jid == actor or self.config.jids_equal(actor, jid) then
+ if jid == actor or self:jids_equal(actor, jid) then
cap = "get_subscription";
else
cap = "get_subscription_other";
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)
return false, "item-not-found";
end
if id then -- Restrict results to a single specific item
- return true, { node_obj.data[id] };
+ return true, { [id] = node_obj.data[id] };
else
return true, node_obj.data;
end
return true, self.nodes;
end
+function service:get_subscriptions(node, actor, jid)
+ -- Access checking
+ local cap;
+ if 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