1 module("pubsub", package.seeall);
4 local service_mt = { __index = service };
6 local default_config = {
7 broadcaster = function () end;
8 get_affiliation = function () end;
13 config = config or {};
15 config = setmetatable(config, { __index = default_config });
21 function service:may(node, actor, action)
22 if actor == true then return true; end
25 local node_obj = self.nodes[node];
26 local node_aff = node_obj and node_obj.affiliations[actor];
27 local service_aff = self.affiliations[actor]
28 or self.config.get_affiliation(actor, node, action)
31 local node_capabilities = node_obj and node_obj.capabilities;
32 local service_capabilities = self.config.capabilities;
34 -- Check if node allows/forbids it
35 if node_capabilities then
36 local caps = node_capabilities[node_aff or service_aff];
38 local can = caps[action];
44 -- Check service-wide capabilities instead
45 local caps = service_capabilities[node_aff or service_aff];
47 local can = caps[action];
56 function service:set_affiliation(node, actor, jid, affiliation)
58 if not self:may(node, actor, "set_affiliation") then
59 return false, "forbidden";
62 local node_obj = self.nodes[node];
64 return false, "item-not-found";
66 node_obj.affiliations[jid] = affiliation;
67 local _, jid_sub = self:get_subscription(node, nil, jid);
68 if not jid_sub and not self:may(node, jid, "be_unsubscribed") then
69 local ok, err = self:add_subscription(node, nil, jid);
73 elseif jid_sub and not self:may(node, jid, "be_subscribed") then
74 local ok, err = self:add_subscription(node, nil, jid);
82 function service:add_subscription(node, actor, jid, options)
85 if jid == actor or self.config.jids_equal(actor, jid) then
88 cap = "subscribe_other";
90 if not self:may(node, actor, cap) then
91 return false, "forbidden";
93 if not self:may(node, jid, "be_subscribed") then
94 return false, "forbidden";
97 local node_obj = self.nodes[node];
99 if not self.config.autocreate_on_subscribe then
100 return false, "item-not-found";
102 local ok, err = self:create(node, actor);
108 node_obj.subscribers[jid] = options or true;
112 function service:remove_subscription(node, actor, jid)
115 if jid == actor or self.config.jids_equal(actor, jid) then
118 cap = "unsubscribe_other";
120 if not self:may(node, actor, cap) then
121 return false, "forbidden";
123 if not self:may(node, jid, "be_unsubscribed") then
124 return false, "forbidden";
127 local node_obj = self.nodes[node];
129 return false, "item-not-found";
131 if not node_obj.subscribers[jid] then
132 return false, "not-subscribed";
134 node_obj.subscribers[jid] = nil;
138 function service:get_subscription(node, actor, jid)
141 if jid == actor or self.config.jids_equal(actor, jid) then
142 cap = "get_subscription";
144 cap = "get_subscription_other";
146 if not self:may(node, actor, cap) then
147 return false, "forbidden";
150 local node_obj = self.nodes[node];
152 return true, node_obj.subscribers[jid];
156 function service:create(node, actor)
158 if not self:may(node, actor, "create") then
159 return false, "forbidden";
162 if self.nodes[node] then
163 return false, "conflict";
173 local ok, err = self:set_affiliation(node, true, actor, "owner");
175 self.nodes[node] = nil;
180 function service:publish(node, actor, id, item)
182 if not self:may(node, actor, "publish") then
183 return false, "forbidden";
186 local node_obj = self.nodes[node];
188 if not self.config.autocreate_on_publish then
189 return false, "item-not-found";
191 local ok, err = self:create(node, actor);
195 node_obj = self.nodes[node];
197 node_obj.data[id] = item;
198 self.config.broadcaster(node, node_obj.subscribers, item);
202 function service:retract(node, actor, id, retract)
204 if not self:may(node, actor, "retract") then
205 return false, "forbidden";
208 local node_obj = self.nodes[node];
209 if (not node_obj) or (not node_obj.data[id]) then
210 return false, "item-not-found";
212 node_obj.data[id] = nil;
214 self.config.broadcaster(node, node_obj.subscribers, retract);
219 function service:get_items(node, actor, id)
221 if not self:may(node, actor, "get_items") then
222 return false, "forbidden";
225 local node_obj = self.nodes[node];
227 return false, "item-not-found";
229 if id then -- Restrict results to a single specific item
230 return true, { node_obj.data[id] };
232 return true, node_obj.data;
236 function service:get_nodes(actor)
238 if not self:may(nil, actor, "get_nodes") then
239 return false, "forbidden";
242 return true, self.nodes;