mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
PubSub improvements
This commit contains - code cleanup - use of db_type instead of old mod_pubsub_odbc - some minor optimizations - some minor bugfixes
This commit is contained in:
parent
63926efd20
commit
e0563e3918
@ -27,8 +27,7 @@
|
||||
|
||||
%% -------------------------------
|
||||
%% Pubsub constants
|
||||
-define(ERR_EXTENDED(E, C),
|
||||
mod_pubsub:extended_error(E, C)).
|
||||
-define(ERR_EXTENDED(E, C), mod_pubsub:extended_error(E, C)).
|
||||
|
||||
%% The actual limit can be configured with mod_pubsub's option max_items_node
|
||||
-define(MAXITEMS, 10).
|
||||
@ -40,7 +39,6 @@
|
||||
%% -------------------------------
|
||||
%% Pubsub types
|
||||
|
||||
%% @type hostPubsub() = string().
|
||||
-type(hostPubsub() :: binary()).
|
||||
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
||||
%% <tt>"pubsub.localhost"</tt>.</p>
|
||||
@ -60,11 +58,14 @@
|
||||
%% @type nodeId() = binary().
|
||||
%% <p>A node is defined by a list of its ancestors. The last element is the name
|
||||
%% of the current node. For example:
|
||||
%% of the current node. For example:
|
||||
%% ```<<"/home/localhost/user">>'''</p>
|
||||
|
||||
-type(nodeIdx() :: pos_integer()).
|
||||
%% @type nodeIdx() = integer().
|
||||
-type(nodeIdx() :: pos_integer() | binary()).
|
||||
%% @type nodeIdx() = integer() | binary().
|
||||
%% note: pos_integer() should always be used, but we allow anything else coded
|
||||
%% as binary, so one can have a custom implementation of nodetree with custom
|
||||
%% indexing (see nodetree_virtual). this also allows to use any kind of key for
|
||||
%% indexing nodes, as this can be usefull with external backends such as odbc.
|
||||
|
||||
-type(itemId() :: binary()).
|
||||
%% @type itemId() = string().
|
||||
@ -72,28 +73,12 @@
|
||||
-type(subId() :: binary()).
|
||||
%% @type subId() = string().
|
||||
|
||||
|
||||
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
|
||||
|
||||
%% @type stanzaError() = #xmlelement{}.
|
||||
%% Example:
|
||||
%% Example:
|
||||
%% ```{xmlelement, "error",
|
||||
%% [{"code", Code}, {"type", Type}],
|
||||
%% [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}'''
|
||||
%% @type pubsubIQResponse() = #xmlelement{}.
|
||||
%% Example:
|
||||
%% ```{xmlelement, "pubsub",
|
||||
%% [{"xmlns", ?NS_PUBSUB_EVENT}],
|
||||
%% [{xmlelement, "affiliations", [],
|
||||
%% []}]}'''
|
||||
|
||||
-type(nodeOption() ::
|
||||
{Option::atom(),
|
||||
Value::binary() | [binary()] | boolean() | non_neg_integer()
|
||||
Value::atom() | [binary()] | boolean() | non_neg_integer()
|
||||
}).
|
||||
|
||||
-type(nodeOptions() :: [NodeOption::mod_pubsub:nodeOption(),...]).
|
||||
-type(nodeOptions() :: [mod_pubsub:nodeOption(),...]).
|
||||
|
||||
%% @type nodeOption() = {Option, Value}
|
||||
%% Option = atom()
|
||||
@ -106,26 +91,9 @@
|
||||
Value::binary() | [binary()] | boolean()
|
||||
}).
|
||||
|
||||
-type(subOptions() :: [SubOption::mod_pubsub:subOption(),...]).
|
||||
-type(subOptions() :: [mod_pubsub:subOption(),...]).
|
||||
|
||||
%% @type nodeType() = string().
|
||||
%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub
|
||||
%% plugin to use to manage a given node. For example, it can be
|
||||
%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p>
|
||||
|
||||
%% @type jid() = {jid, User, Server, Resource, LUser, LServer, LResource}
|
||||
%% User = string()
|
||||
%% Server = string()
|
||||
%% Resource = string()
|
||||
%% LUser = string()
|
||||
%% LServer = string()
|
||||
%% LResource = string().
|
||||
|
||||
%-type(ljid() :: {binary(), binary(), binary()}).
|
||||
%% @type ljid() = {User, Server, Resource}
|
||||
%% User = string()
|
||||
%% Server = string()
|
||||
%% Resource = string().
|
||||
|
||||
-type(affiliation() :: 'none'
|
||||
| 'owner'
|
||||
@ -151,16 +119,11 @@
|
||||
).
|
||||
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
||||
|
||||
%% @type pubsubIndex() = {pubsub_index, Index, Last, Free}
|
||||
%% Index = atom()
|
||||
%% Last = integer()
|
||||
%% Free = [integer()].
|
||||
%% internal pubsub index table
|
||||
-type(publishModel() :: 'publishers'
|
||||
| 'subscribers'
|
||||
| 'open'
|
||||
).
|
||||
|
||||
%% @type publishModel() = 'publishers' | 'subscribers' | 'open'
|
||||
|
||||
-record(pubsub_index,
|
||||
{
|
||||
@ -169,91 +132,42 @@
|
||||
free :: [mod_pubsub:nodeIdx()]
|
||||
}).
|
||||
|
||||
%% @type pubsubNode() = {pubsub_node, NodeId, Id, Parents, Type, Owners, Options}
|
||||
%% NodeId = {host() | ljid(), nodeId()}
|
||||
%% Id = nodeIdx()
|
||||
%% Parents = [nodeId()]
|
||||
%% Type = nodeType()
|
||||
%% Owners = [ljid()]
|
||||
%% Options = [nodeOption()].
|
||||
%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
|
||||
%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
%% <p>The <tt>Parents</tt> and <tt>type</tt> fields are indexed.</p>
|
||||
%% <tt>id</tt> can be anything you want.
|
||||
-record(pubsub_node,
|
||||
{
|
||||
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
|
||||
id ,%:: mod_pubsub:nodeIdx(),
|
||||
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()],
|
||||
type = <<"flat">> ,%:: binary(),
|
||||
owners = [] ,%:: [Owner::ljid(),...],
|
||||
options = [] %:: mod_pubsub:nodeOptions()
|
||||
nodeid ,% :: {mod_pubsub:host(), mod_pubsub:nodeId()},
|
||||
id ,% :: mod_pubsub:nodeIdx(),
|
||||
parents = [] ,% :: [mod_pubsub:nodeId(),...],
|
||||
type = <<"flat">>,% :: binary(),
|
||||
owners = [] ,% :: [jlib:ljid(),...],
|
||||
options = [] % :: mod_pubsub:nodeOptions()
|
||||
}).
|
||||
|
||||
%% @type pubsubState() = {pubsub_state, StateId, Items, Affiliation, Subscriptions}
|
||||
%% StateId = {ljid(), nodeIdx()}
|
||||
%% Items = [itemId()]
|
||||
%% Affiliation = affiliation()
|
||||
%% Subscriptions = [{subscription(), subId()}].
|
||||
%% <p>This is the format of the <tt>affiliations</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
|
||||
%-record(pubsub_state,
|
||||
% {stateid, items = [], affiliation = none,
|
||||
% subscriptions = []}).
|
||||
-record(pubsub_state,
|
||||
{
|
||||
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()},
|
||||
items = [] ,%:: [ItemId::mod_pubsub:itemId()],
|
||||
affiliation = 'none' ,%:: mod_pubsub:affiliation(),
|
||||
subscriptions = [] %:: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
||||
stateid ,% :: {jlib:ljid(), mod_pubsub:nodeIdx()},
|
||||
items = [] ,% :: [mod_pubsub:itemId(),...],
|
||||
affiliation = 'none',% :: mod_pubsub:affiliation(),
|
||||
subscriptions = [] % :: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
||||
}).
|
||||
|
||||
%% @type pubsubItem() = {pubsub_item, ItemId, Creation, Modification, Payload}
|
||||
%% ItemId = {itemId(), nodeIdx()}
|
||||
%% Creation = {now(), ljid()}
|
||||
%% Modification = {now(), ljid()}
|
||||
%% Payload = payload().
|
||||
%% <p>This is the format of the <tt>published items</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
|
||||
%-record(pubsub_item,
|
||||
% {itemid, creation = {unknown, unknown},
|
||||
% modification = {unknown, unknown}, payload = []}).
|
||||
|
||||
-record(pubsub_item,
|
||||
{
|
||||
itemid ,%:: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
||||
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
payload = [] %:: mod_pubsub:payload()
|
||||
itemid ,% :: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
||||
creation = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
|
||||
modification = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
|
||||
payload = [] % :: mod_pubsub:payload()
|
||||
}).
|
||||
|
||||
%% @type pubsubSubscription() = {pubsub_subscription, SubId, Options}
|
||||
%% SubId = subId()
|
||||
%% Options = [nodeOption()].
|
||||
%% <p>This is the format of the <tt>subscriptions</tt> table. The type of the
|
||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
%-record(pubsub_subscription, {subid, options}).
|
||||
-record(pubsub_subscription,
|
||||
{
|
||||
subid ,%:: mod_pubsub:subId(),
|
||||
options %:: [] | mod_pubsub:subOptions()
|
||||
subid ,% :: mod_pubsub:subId(),
|
||||
options = [] % :: mod_pubsub:subOptions()
|
||||
}).
|
||||
|
||||
%% @type pubsubLastItem() = {pubsub_last_item, NodeId, ItemId, Creation, Payload}
|
||||
%% NodeId = nodeIdx()
|
||||
%% ItemId = itemId()
|
||||
%% Creation = {now(),ljid()}
|
||||
%% Payload = payload().
|
||||
%% <p>This is the format of the <tt>last items</tt> table. it stores last item payload
|
||||
%% for every node</p>
|
||||
%-record(pubsub_last_item,
|
||||
% {nodeid, itemid, creation, payload}).
|
||||
|
||||
-record(pubsub_last_item,
|
||||
{
|
||||
nodeid ,%:: mod_pubsub:nodeIdx(),
|
||||
itemid ,%:: mod_pubsub:itemId(),
|
||||
creation ,%:: {erlang:timestamp(), ljid()},
|
||||
payload %:: mod_pubsub:payload()
|
||||
nodeid ,% :: mod_pubsub:nodeIdx(),
|
||||
itemid ,% :: mod_pubsub:itemId(),
|
||||
creation ,% :: {erlang:timestamp(), jlib:ljid()},
|
||||
payload % :: mod_pubsub:payload()
|
||||
}).
|
||||
|
@ -32,191 +32,146 @@
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-type(host() :: mod_pubsub:host()
|
||||
| mod_pubsub_odbc:host()
|
||||
).
|
||||
|
||||
-type(nodeId() :: mod_pubsub:nodeId()
|
||||
| mod_pubsub_odbc:nodeId()
|
||||
).
|
||||
|
||||
-type(nodeIdx() :: mod_pubsub:nodeIdx()
|
||||
| mod_pubsub_odbc:nodeIdx()
|
||||
).
|
||||
|
||||
-type(itemId() :: mod_pubsub:itemId()
|
||||
| mod_pubsub_odbc:itemId()
|
||||
).
|
||||
|
||||
-type(pubsubNode() :: mod_pubsub:pubsubNode()
|
||||
| mod_pubsub_odbc:pubsubNode()
|
||||
).
|
||||
|
||||
-type(pubsubState() :: mod_pubsub:pubsubState()
|
||||
| mod_pubsub_odbc:pubsubState()
|
||||
).
|
||||
|
||||
-type(pubsubItem() :: mod_pubsub:pubsubItem()
|
||||
| mod_pubsub_odbc:pubsubItem()
|
||||
).
|
||||
|
||||
-type(nodeOptions() :: mod_pubsub:nodeOptions()
|
||||
| mod_pubsub_odbc:nodeOptions()
|
||||
).
|
||||
|
||||
-type(subOptions() :: mod_pubsub:subOptions()
|
||||
| mod_pubsub_odbc:subOptions()
|
||||
).
|
||||
|
||||
-type(affiliation() :: mod_pubsub:affiliation()
|
||||
| mod_pubsub_odbc:affiliation()
|
||||
).
|
||||
|
||||
-type(subscription() :: mod_pubsub:subscription()
|
||||
| mod_pubsub_odbc:subscription()
|
||||
).
|
||||
|
||||
-type(subId() :: mod_pubsub:subId()
|
||||
| mod_pubsub_odbc:subId()
|
||||
).
|
||||
|
||||
-type(accessModel() :: mod_pubsub:accessModel()
|
||||
| mod_pubsub_odbc:accessModel()
|
||||
).
|
||||
|
||||
-type(publishModel() :: mod_pubsub:publishModel()
|
||||
| mod_pubsub_odbc:publishModel()
|
||||
).
|
||||
|
||||
-type(payload() :: mod_pubsub:payload()
|
||||
| mod_pubsub_odbc:payload()
|
||||
).
|
||||
-type(host() :: mod_pubsub:host()).
|
||||
-type(nodeId() :: mod_pubsub:nodeId()).
|
||||
-type(nodeIdx() :: mod_pubsub:nodeIdx()).
|
||||
-type(itemId() :: mod_pubsub:itemId()).
|
||||
-type(pubsubNode() :: mod_pubsub:pubsubNode()).
|
||||
-type(pubsubState() :: mod_pubsub:pubsubState()).
|
||||
-type(pubsubItem() :: mod_pubsub:pubsubItem()).
|
||||
-type(subOptions() :: mod_pubsub:subOptions()).
|
||||
-type(affiliation() :: mod_pubsub:affiliation()).
|
||||
-type(subscription() :: mod_pubsub:subscription()).
|
||||
-type(subId() :: mod_pubsub:subId()).
|
||||
-type(accessModel() :: mod_pubsub:accessModel()).
|
||||
-type(publishModel() :: mod_pubsub:publishModel()).
|
||||
-type(payload() :: mod_pubsub:payload()).
|
||||
|
||||
-callback init(Host :: binary(),
|
||||
ServerHost :: binary(),
|
||||
Opts :: [any()]) -> atom().
|
||||
ServerHost :: binary(),
|
||||
Opts :: [any()]) -> atom().
|
||||
|
||||
-callback terminate(Host :: host(),
|
||||
ServerHost :: binary()) -> atom().
|
||||
ServerHost :: binary()) -> atom().
|
||||
|
||||
-callback options() -> [{atom(), any()}].
|
||||
|
||||
-callback features() -> [binary()].
|
||||
|
||||
-callback create_node_permission(Host :: host(),
|
||||
ServerHost :: binary(),
|
||||
Node :: nodeId(),
|
||||
ParentNode :: nodeId(),
|
||||
Owner :: jid(), Access :: atom()) ->
|
||||
ServerHost :: binary(),
|
||||
Node :: nodeId(),
|
||||
ParentNode :: nodeId(),
|
||||
Owner :: jid(), Access :: atom()) ->
|
||||
{result, boolean()}.
|
||||
|
||||
-callback create_node(NodeIdx :: nodeIdx(),
|
||||
Owner :: jid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, {default, broadcast}}.
|
||||
|
||||
-callback delete_node(Nodes :: [pubsubNode(),...]) ->
|
||||
{result,
|
||||
{default, broadcast,
|
||||
[{pubsubNode(),
|
||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||
}
|
||||
}
|
||||
{default, broadcast,
|
||||
[{pubsubNode(),
|
||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||
}
|
||||
}
|
||||
|
|
||||
{result,
|
||||
{[],
|
||||
[{pubsubNode(),
|
||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||
}
|
||||
}.
|
||||
{[],
|
||||
[{pubsubNode(),
|
||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||
}
|
||||
}.
|
||||
|
||||
-callback purge_node(NodeIdx :: nodeIdx(),
|
||||
Owner :: jid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, {default, broadcast}} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback subscribe_node(NodeIdx :: nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: ljid(),
|
||||
AccessModel :: accessModel(),
|
||||
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
Options :: subOptions()) ->
|
||||
Sender :: jid(),
|
||||
Subscriber :: jid(),
|
||||
AccessModel :: accessModel(),
|
||||
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
Options :: subOptions()) ->
|
||||
{result, {default, subscribed, subId()}} |
|
||||
{result, {default, subscribed, subId(), send_last}} |
|
||||
{result, {default, pending, subId()}} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback unsubscribe_node(NodeIdx :: nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: ljid(),
|
||||
SubId :: subId()) ->
|
||||
Sender :: jid(),
|
||||
Subscriber :: jid(),
|
||||
SubId :: subId()) ->
|
||||
{result, default} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback publish_item(NodeId :: nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: publishModel(),
|
||||
Max_Items :: non_neg_integer(),
|
||||
ItemId :: <<>> | itemId(),
|
||||
Payload :: payload()) ->
|
||||
Publisher :: jid(),
|
||||
PublishModel :: publishModel(),
|
||||
Max_Items :: non_neg_integer(),
|
||||
ItemId :: <<>> | itemId(),
|
||||
Payload :: payload()) ->
|
||||
{result, {default, broadcast, [itemId()]}} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback delete_item(NodeIdx :: nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: publishModel(),
|
||||
ItemId :: <<>> | itemId()) ->
|
||||
Publisher :: jid(),
|
||||
PublishModel :: publishModel(),
|
||||
ItemId :: <<>> | itemId()) ->
|
||||
{result, {default, broadcast}} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback remove_extra_items(NodeIdx :: nodeIdx(),
|
||||
Max_Items :: unlimited | non_neg_integer(),
|
||||
ItemIds :: [itemId()]) ->
|
||||
Max_Items :: unlimited | non_neg_integer(),
|
||||
ItemIds :: [itemId()]) ->
|
||||
{result, {[itemId()], [itemId()]}
|
||||
}.
|
||||
}.
|
||||
|
||||
-callback get_node_affiliations(NodeIdx :: nodeIdx()) ->
|
||||
{result, [{ljid(), affiliation()}]}.
|
||||
|
||||
-callback get_entity_affiliations(Host :: host(),
|
||||
Owner :: jid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, [{pubsubNode(), affiliation()}]}.
|
||||
|
||||
-callback get_affiliation(NodeIdx :: nodeIdx(),
|
||||
Owner :: jid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, affiliation()}.
|
||||
|
||||
-callback set_affiliation(NodeIdx :: nodeIdx(),
|
||||
Owner :: ljid(),
|
||||
Affiliation :: affiliation()) ->
|
||||
Owner :: jid(),
|
||||
Affiliation :: affiliation()) ->
|
||||
ok |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_node_subscriptions(NodeIdx :: nodeIdx()) ->
|
||||
{result,
|
||||
[{ljid(), subscription(), subId()}] |
|
||||
[{ljid(), none},...]
|
||||
}.
|
||||
[{ljid(), subscription(), subId()}] |
|
||||
[{ljid(), none},...]
|
||||
}.
|
||||
|
||||
-callback get_entity_subscriptions(Host :: host(),
|
||||
Owner :: jid()) ->
|
||||
Key :: jid()) ->
|
||||
{result, [{pubsubNode(), subscription(), subId(), ljid()}]
|
||||
}.
|
||||
}.
|
||||
|
||||
-callback get_subscriptions(NodeIdx :: nodeIdx(),
|
||||
Owner :: ljid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, [{subscription(), subId()}]}.
|
||||
|
||||
-callback get_pending_nodes(Host :: host(),
|
||||
Owner :: jid()) ->
|
||||
Owner :: jid()) ->
|
||||
{result, [nodeId()]}.
|
||||
|
||||
-callback get_states(NodeIdx::nodeIdx()) ->
|
||||
{result, [pubsubState()]}.
|
||||
|
||||
-callback get_state(NodeIdx :: nodeIdx(),
|
||||
JID :: ljid()) ->
|
||||
Key :: ljid()) ->
|
||||
pubsubState().
|
||||
|
||||
-callback set_state(State::pubsubState()) ->
|
||||
@ -224,30 +179,32 @@
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_items(NodeIdx :: nodeIdx(),
|
||||
JID :: jid(),
|
||||
AccessModel :: accessModel(),
|
||||
Presence_Subscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
SubId :: subId()) ->
|
||||
{result, [pubsubItem()]} |
|
||||
JID :: jid(),
|
||||
AccessModel :: accessModel(),
|
||||
Presence_Subscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
SubId :: subId(),
|
||||
RSM :: none | rsm_in()) ->
|
||||
{result, {[pubsubItem()], none | rsm_out()}} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_items(NodeIdx :: nodeIdx(),
|
||||
From :: jid()) ->
|
||||
{result, [pubsubItem()]}.
|
||||
From :: jid(),
|
||||
RSM :: none | rsm_in()) ->
|
||||
{result, {[pubsubItem()], none | rsm_out()}}.
|
||||
|
||||
-callback get_item(NodeIdx :: nodeIdx(),
|
||||
ItemId :: itemId(),
|
||||
JID :: jid(),
|
||||
AccessModel :: accessModel(),
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
SubId :: subId()) ->
|
||||
ItemId :: itemId(),
|
||||
JID :: jid(),
|
||||
AccessModel :: accessModel(),
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
SubId :: subId()) ->
|
||||
{result, pubsubItem()} |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_item(NodeIdx :: nodeIdx(),
|
||||
ItemId :: itemId()) ->
|
||||
ItemId :: itemId()) ->
|
||||
{result, pubsubItem()} |
|
||||
{error, xmlel()}.
|
||||
|
||||
@ -256,8 +213,8 @@
|
||||
% | {error, _}.
|
||||
|
||||
-callback get_item_name(Host :: host(),
|
||||
ServerHost :: binary(),
|
||||
Node :: nodeId()) ->
|
||||
ServerHost :: binary(),
|
||||
Node :: nodeId()) ->
|
||||
itemId().
|
||||
|
||||
-callback node_to_path(Node :: nodeId()) ->
|
||||
|
@ -32,49 +32,31 @@
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-type(host() :: mod_pubsub:host()
|
||||
| mod_pubsub_odbc:host()
|
||||
).
|
||||
|
||||
-type(nodeId() :: mod_pubsub:nodeId()
|
||||
| mod_pubsub_odbc:nodeId()
|
||||
).
|
||||
|
||||
-type(nodeIdx() :: mod_pubsub:nodeIdx()
|
||||
| mod_pubsub_odbc:nodeIdx()
|
||||
).
|
||||
|
||||
-type(itemId() :: mod_pubsub:itemId()
|
||||
| mod_pubsub_odbc:itemId()
|
||||
).
|
||||
|
||||
-type(pubsubNode() :: mod_pubsub:pubsubNode()
|
||||
| mod_pubsub_odbc:pubsubNode()
|
||||
).
|
||||
|
||||
-type(nodeOptions() :: mod_pubsub:nodeOptions()
|
||||
| mod_pubsub_odbc:nodeOptions()
|
||||
).
|
||||
-type(host() :: mod_pubsub:host()).
|
||||
-type(nodeId() :: mod_pubsub:nodeId()).
|
||||
-type(nodeIdx() :: mod_pubsub:nodeIdx()).
|
||||
-type(pubsubNode() :: mod_pubsub:pubsubNode()).
|
||||
-type(nodeOptions() :: mod_pubsub:nodeOptions()).
|
||||
|
||||
-callback init(Host :: host(),
|
||||
ServerHost :: binary(),
|
||||
Opts :: [any()]) -> atom().
|
||||
ServerHost :: binary(),
|
||||
Opts :: [any()]) -> atom().
|
||||
|
||||
-callback terminate(Host :: host(), ServerHost :: binary()) -> atom().
|
||||
|
||||
-callback options() -> nodeOptions().
|
||||
|
||||
-callback set_node(PubsubNode :: pubsubNode()) ->
|
||||
ok | {result, NodeIdx::mod_pubsub_odbc:nodeIdx()} | {error, xmlel()}.
|
||||
ok | {result, NodeIdx::nodeIdx()} | {error, xmlel()}.
|
||||
|
||||
-callback get_node(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
pubsubNode() |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_node(Host :: host(),
|
||||
NodeId :: nodeId()) ->
|
||||
NodeId :: nodeId()) ->
|
||||
pubsubNode() |
|
||||
{error, xmlel()}.
|
||||
|
||||
@ -83,42 +65,43 @@
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_nodes(Host :: host(),
|
||||
From :: jid())->
|
||||
From :: jid())->
|
||||
[pubsubNode()].
|
||||
|
||||
-callback get_nodes(Host :: host())->
|
||||
[pubsubNode()].
|
||||
|
||||
-callback get_parentnodes(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
[pubsubNode()] |
|
||||
{error, xmlel()}.
|
||||
|
||||
-callback get_parentnodes_tree(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
[{0, [pubsubNode(),...]}].
|
||||
|
||||
-callback get_subnodes(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
From :: ljid()) ->
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
[pubsubNode()].
|
||||
|
||||
-callback get_subnodes_tree(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
From :: ljid()) ->
|
||||
NodeId :: nodeId(),
|
||||
From :: jid()) ->
|
||||
[pubsubNode()].
|
||||
|
||||
-callback create_node(Host :: host(),
|
||||
NodeId :: nodeId(),
|
||||
Type :: binary(),
|
||||
Owner :: jid(),
|
||||
Options :: nodeOptions(),
|
||||
Parents :: [nodeId()]) ->
|
||||
NodeId :: nodeId(),
|
||||
Type :: binary(),
|
||||
Owner :: jid(),
|
||||
Options :: nodeOptions(),
|
||||
Parents :: [nodeId()]) ->
|
||||
{ok, NodeIdx::nodeIdx()} |
|
||||
{error, xmlel()}.
|
||||
{error, xmlel()} |
|
||||
{error, {virtual, {host(), nodeId()}}}.
|
||||
|
||||
-callback delete_node(Host :: host(),
|
||||
NodeId :: nodeId()) ->
|
||||
NodeId :: nodeId()) ->
|
||||
[pubsubNode()].
|
||||
|
7343
src/mod_pubsub.erl
7343
src/mod_pubsub.erl
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,194 +0,0 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(__TO_BE_DEFINED__).
|
||||
-author(__TO_BE_DEFINED__).
|
||||
|
||||
-include("pubsub.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% Note on function definition
|
||||
%% included is all defined plugin function
|
||||
%% it's possible not to define some function at all
|
||||
%% in that case, warning will be generated at compilation
|
||||
%% and function call will fail,
|
||||
%% then mod_pubsub will call function from node_hometree
|
||||
%% (this makes code cleaner, but execution a little bit longer)
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2,
|
||||
options/0, features/0,
|
||||
create_node_permission/6,
|
||||
create_node/2,
|
||||
delete_node/1,
|
||||
purge_node/2,
|
||||
subscribe_node/8,
|
||||
unsubscribe_node/4,
|
||||
publish_item/6,
|
||||
delete_item/4,
|
||||
remove_extra_items/3,
|
||||
get_entity_affiliations/2,
|
||||
get_node_affiliations/1,
|
||||
get_affiliation/2,
|
||||
set_affiliation/3,
|
||||
get_entity_subscriptions/2,
|
||||
get_node_subscriptions/1,
|
||||
get_subscriptions/2,
|
||||
set_subscriptions/4,
|
||||
get_pending_nodes/2,
|
||||
get_states/1,
|
||||
get_state/2,
|
||||
set_state/1,
|
||||
get_items/6,
|
||||
get_items/2,
|
||||
get_item/7,
|
||||
get_item/2,
|
||||
set_item/1,
|
||||
get_item_name/3
|
||||
]).
|
||||
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
|
||||
terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, open},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
["create-nodes",
|
||||
"delete-nodes",
|
||||
"delete-items",
|
||||
"instant-nodes",
|
||||
"outcast-affiliation",
|
||||
"persistent-items",
|
||||
"publish",
|
||||
"purge-nodes",
|
||||
"retract-items",
|
||||
"retrieve-affiliations",
|
||||
"retrieve-items",
|
||||
"retrieve-subscriptions",
|
||||
"subscribe",
|
||||
"subscription-notifications"
|
||||
].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) ->
|
||||
node_hometree:get_states(NodeId).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
|
||||
get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
@ -17,45 +17,32 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_buddy).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% Note on function definition
|
||||
%% included is all defined plugin function
|
||||
%% it's possible not to define some function at all
|
||||
%% in that case, warning will be generated at compilation
|
||||
%% and function call will fail,
|
||||
%% then mod_pubsub will call function from node_hometree
|
||||
%% (this makes code cleaner, but execution a little bit longer)
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -64,121 +51,127 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, presence}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, presence},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
||||
<<"delete-items">>, <<"instant-nodes">>, <<"item-ids">>,
|
||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost,
|
||||
Node, ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
@ -1,4 +1,4 @@
|
||||
%%% ====================================================================
|
||||
%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
@ -17,45 +17,32 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_club).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% Note on function definition
|
||||
%% included is all defined plugin function
|
||||
%% it's possible not to define some function at all
|
||||
%% in that case, warning will be generated at compilation
|
||||
%% and function call will fail,
|
||||
%% then mod_pubsub will call function from node_hometree
|
||||
%% (this makes code cleaner, but execution a little bit longer)
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -64,121 +51,126 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, authorize}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, authorize},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
||||
<<"delete-items">>, <<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost,
|
||||
Node, ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
161
src/node_dag.erl
161
src/node_dag.erl
@ -5,39 +5,37 @@
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%%
|
||||
%%% @author Brian Cully <bjc@kublai.com>
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_dag).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('bjc@kublai.com').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -51,113 +49,108 @@ options() ->
|
||||
features() ->
|
||||
[<<"multi-collection">> | node_hometree:features()].
|
||||
|
||||
create_node_permission(_Host, _ServerHost, _Node,
|
||||
_ParentNode, _Owner, _Access) ->
|
||||
create_node_permission(_Host, _ServerHost, _Node, _ParentNode, _Owner, _Access) ->
|
||||
{result, true}.
|
||||
|
||||
create_node(NodeID, Owner) ->
|
||||
node_hometree:create_node(NodeID, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeID, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeID, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeID, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeID, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeID, Publisher, Model, MaxItems, ItemID,
|
||||
Payload) ->
|
||||
case nodetree_dag:get_node(NodeID) of
|
||||
#pubsub_node{options = Options} ->
|
||||
case find_opt(node_type, Options) of
|
||||
collection ->
|
||||
{error,
|
||||
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)};
|
||||
_ ->
|
||||
node_hometree:publish_item(NodeID, Publisher, Model,
|
||||
MaxItems, ItemID, Payload)
|
||||
end;
|
||||
Err -> Err
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
case nodetree_dag:get_node(Nidx) of
|
||||
#pubsub_node{options = Options} ->
|
||||
case find_opt(node_type, Options) of
|
||||
collection ->
|
||||
{error,
|
||||
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)};
|
||||
_ ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model,
|
||||
MaxItems, ItemId, Payload)
|
||||
end;
|
||||
Err -> Err
|
||||
end.
|
||||
|
||||
find_opt(_, []) -> false;
|
||||
find_opt(Option, [{Option, Value} | _]) -> Value;
|
||||
find_opt(Option, [_ | T]) -> find_opt(Option, T).
|
||||
|
||||
remove_extra_items(NodeID, MaxItems, ItemIDs) ->
|
||||
node_hometree:remove_extra_items(NodeID, MaxItems,
|
||||
ItemIDs).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeID, Publisher, PublishModel, ItemID) ->
|
||||
node_hometree:delete_item(NodeID, Publisher,
|
||||
PublishModel, ItemID).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeID, Owner) ->
|
||||
node_hometree:purge_node(NodeID, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeID) ->
|
||||
node_hometree:get_node_affiliations(NodeID).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeID, Owner) ->
|
||||
node_hometree:get_affiliation(NodeID, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeID, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeID, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeID) ->
|
||||
node_hometree:get_node_subscriptions(NodeID).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeID, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeID, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeID, Owner, Subscription, SubID) ->
|
||||
node_hometree:set_subscriptions(NodeID, Owner,
|
||||
Subscription, SubID).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeID) -> node_hometree:get_states(NodeID).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeID, JID) ->
|
||||
node_hometree:get_state(NodeID, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeID, From) ->
|
||||
node_hometree:get_items(NodeID, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeID, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubID) ->
|
||||
node_hometree:get_items(NodeID, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubID).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeID, ItemID) ->
|
||||
node_hometree:get_item(NodeID, ItemID).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeID, ItemID, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubID) ->
|
||||
node_hometree:get_item(NodeID, ItemID, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubID).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, ID) ->
|
||||
node_hometree:get_item_name(Host, Node, ID).
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_hometree:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_hometree:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_hometree:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_hometree:path_to_node(Path).
|
||||
|
@ -17,43 +17,38 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_dispatch).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%%% @doc <p>The <strong>{@module}</strong> module is a PubSub plugin whose
|
||||
%%% goal is to republished each published item to all its children.</p>
|
||||
%%% <p>Users cannot subscribe to this node, but are supposed to subscribe to
|
||||
%%% its children.</p>
|
||||
%%% This module can not work with virtual nodetree
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -62,115 +57,129 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, open}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, presence},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
||||
<<"instant-nodes">>, <<"outcast-affiliation">>,
|
||||
<<"persistent-items">>, <<"publish">>,
|
||||
<<"retrieve-items">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"retrieve-items">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost,
|
||||
Node, ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
delete_node(Nodes) ->
|
||||
node_hometree:delete_node(Nodes).
|
||||
|
||||
subscribe_node(_NodeId, _Sender, _Subscriber,
|
||||
_AccessModel, _SendLast, _PresenceSubscription,
|
||||
_RosterGroup, _Options) ->
|
||||
subscribe_node(_Nidx, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription,
|
||||
_RosterGroup, _Options) ->
|
||||
{error, ?ERR_FORBIDDEN}.
|
||||
|
||||
unsubscribe_node(_NodeId, _Sender, _Subscriber,
|
||||
_SubID) ->
|
||||
unsubscribe_node(_Nidx, _Sender, _Subscriber, _SubId) ->
|
||||
{error, ?ERR_FORBIDDEN}.
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
lists:foreach(fun (SubNode) ->
|
||||
node_hometree:publish_item(SubNode#pubsub_node.id,
|
||||
Publisher, Model, MaxItems,
|
||||
ItemId, Payload)
|
||||
end,
|
||||
nodetree_tree:get_subnodes(NodeId, Publisher,
|
||||
Publisher)).
|
||||
publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
|
||||
case nodetree_tree:get_node(Nidx) of
|
||||
#pubsub_node{nodeid = {Host, Node}} ->
|
||||
lists:foreach(fun (SubNode) ->
|
||||
node_hometree:publish_item(SubNode#pubsub_node.id,
|
||||
Publisher, PublishModel, MaxItems,
|
||||
ItemId, Payload)
|
||||
end,
|
||||
nodetree_tree:get_subnodes(Host, Node, Publisher)),
|
||||
{result, {default, broadcast, []}};
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
remove_extra_items(_NodeId, _MaxItems, ItemIds) ->
|
||||
remove_extra_items(_Nidx, _MaxItems, ItemIds) ->
|
||||
{result, {ItemIds, []}}.
|
||||
|
||||
delete_item(_NodeId, _Publisher, _PublishModel,
|
||||
_ItemId) ->
|
||||
delete_item(_Nidx, _Publisher, _PublishModel, _ItemId) ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND}.
|
||||
|
||||
purge_node(_NodeId, _Owner) -> {error, ?ERR_FORBIDDEN}.
|
||||
purge_node(_Nidx, _Owner) ->
|
||||
{error, ?ERR_FORBIDDEN}.
|
||||
|
||||
get_entity_affiliations(_Host, _Owner) -> {result, []}.
|
||||
get_entity_affiliations(_Host, _Owner) ->
|
||||
{result, []}.
|
||||
|
||||
get_node_affiliations(_NodeId) -> {result, []}.
|
||||
get_node_affiliations(_Nidx) ->
|
||||
{result, []}.
|
||||
|
||||
get_affiliation(_NodeId, _Owner) -> {result, []}.
|
||||
get_affiliation(_Nidx, _Owner) ->
|
||||
{result, none}.
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(_Host, _Owner) -> {result, []}.
|
||||
get_entity_subscriptions(_Host, _Owner) ->
|
||||
{result, []}.
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(_NodeId, _Owner) -> {result, []}.
|
||||
get_subscriptions(_Nidx, _Owner) ->
|
||||
{result, []}.
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
@ -25,162 +25,156 @@
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_flat).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
pubsub_subscription:init(),
|
||||
mnesia:create_table(pubsub_state,
|
||||
[{disc_copies, [node()]},
|
||||
{type, ordered_set},
|
||||
{attributes, record_info(fields, pubsub_state)}]),
|
||||
mnesia:create_table(pubsub_item,
|
||||
[{disc_only_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_item)}]),
|
||||
ItemsFields = record_info(fields, pubsub_item),
|
||||
case mnesia:table_info(pubsub_item, attributes) of
|
||||
ItemsFields -> ok;
|
||||
_ -> mnesia:transform_table(pubsub_item, ignore, ItemsFields)
|
||||
end,
|
||||
ok.
|
||||
|
||||
terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, open}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
node_hometree:options().
|
||||
|
||||
features() -> node_hometree:features().
|
||||
features() ->
|
||||
node_hometree:features().
|
||||
|
||||
%% use same code as node_hometree, but do not limite node to
|
||||
%% the home/localhost/user/... hierarchy
|
||||
%% any node is allowed
|
||||
create_node_permission(Host, ServerHost, _Node,
|
||||
_ParentNode, Owner, Access) ->
|
||||
create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
|
||||
LOwner = jlib:jid_tolower(Owner),
|
||||
Allowed = case LOwner of
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
_ ->
|
||||
acl:match_rule(ServerHost, Access, LOwner) =:= allow
|
||||
end,
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
_ ->
|
||||
acl:match_rule(ServerHost, Access, LOwner) =:= allow
|
||||
end,
|
||||
{result, Allowed}.
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> [(Node)].
|
||||
node_to_path(Node) ->
|
||||
[(Node)].
|
||||
|
||||
path_to_node(Path) ->
|
||||
case Path of
|
||||
% default slot
|
||||
[Node] -> iolist_to_binary(Node);
|
||||
% handle old possible entries, used when migrating database content to new format
|
||||
[Node | _] when is_binary(Node) ->
|
||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||
% default case (used by PEP for example)
|
||||
_ -> iolist_to_binary(Path)
|
||||
% default slot
|
||||
[Node] -> iolist_to_binary(Node);
|
||||
% handle old possible entries, used when migrating database content to new format
|
||||
[Node | _] when is_binary(Node) ->
|
||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||
% default case (used by PEP for example)
|
||||
_ -> iolist_to_binary(Path)
|
||||
end.
|
||||
|
@ -25,30 +25,25 @@
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_flat_odbc).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2,
|
||||
get_entity_subscriptions_for_send_last/2,
|
||||
get_node_subscriptions/1, get_subscriptions/2,
|
||||
set_subscriptions/4, get_pending_nodes/2, get_states/1,
|
||||
get_state/2, set_state/1, get_items/7, get_items/6,
|
||||
get_items/3, get_items/2, get_item/7, get_item/2,
|
||||
set_item/1, get_item_name/3, get_last_items/3,
|
||||
node_to_path/1, path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1,
|
||||
get_entity_subscriptions_for_send_last/2, get_last_items/3]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree_odbc:init(Host, ServerHost, Opts).
|
||||
@ -57,157 +52,115 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree_odbc:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, open},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}, {odbc, true},
|
||||
{rsm, true}].
|
||||
[{odbc, true}, {rsm, true} | node_flat:options()].
|
||||
|
||||
features() -> node_hometree_odbc:features().
|
||||
features() ->
|
||||
[<<"rsm">> | node_flat:features()].
|
||||
|
||||
%% use same code as node_hometree_odbc, but do not limite node to
|
||||
%% the home/localhost/user/... hierarchy
|
||||
%% any node is allowed
|
||||
create_node_permission(Host, ServerHost, _Node,
|
||||
_ParentNode, Owner, Access) ->
|
||||
LOwner = jlib:jid_tolower(Owner),
|
||||
Allowed = case LOwner of
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
_ ->
|
||||
acl:match_rule(ServerHost, Access, LOwner) =:= allow
|
||||
end,
|
||||
{result, Allowed}.
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_flat:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree_odbc:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree_odbc:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree_odbc:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree_odbc:subscribe_node(NodeId, Sender,
|
||||
Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup,
|
||||
Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree_odbc:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree_odbc:publish_item(NodeId, Publisher,
|
||||
Model, MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree_odbc:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree_odbc:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree_odbc:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree_odbc:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree_odbc:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree_odbc:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree_odbc:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree_odbc:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree_odbc:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree_odbc:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree_odbc:get_entity_subscriptions(Host,
|
||||
Owner).
|
||||
node_hometree_odbc:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_entity_subscriptions_for_send_last(Host, Owner) ->
|
||||
node_hometree_odbc:get_entity_subscriptions_for_send_last(Host,
|
||||
Owner).
|
||||
node_hometree_odbc:get_entity_subscriptions_for_send_last(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree_odbc:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree_odbc:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree_odbc:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree_odbc:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree_odbc:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) ->
|
||||
node_hometree_odbc:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree_odbc:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree_odbc:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree_odbc:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree_odbc:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree_odbc:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree_odbc:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree_odbc:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, From, RSM) ->
|
||||
node_hometree_odbc:get_items(NodeId, From, RSM).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree_odbc:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, none).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree_odbc:get_item(Nidx, ItemId).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree_odbc:get_item(Nidx, ItemId, JID,
|
||||
AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree_odbc:get_item(NodeId, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree_odbc:get_item(NodeId, ItemId, JID,
|
||||
AccessModel, PresenceSubscription, RosterGroup,
|
||||
SubId).
|
||||
|
||||
set_item(Item) -> node_hometree_odbc:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree_odbc:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree_odbc:get_item_name(Host, Node, Id).
|
||||
|
||||
get_last_items(NodeId, From, Count) ->
|
||||
node_hometree_odbc:get_last_items(NodeId, From, Count).
|
||||
get_last_items(Nidx, From, Count) ->
|
||||
node_hometree_odbc:get_last_items(Nidx, From, Count).
|
||||
|
||||
node_to_path(Node) -> [(Node)].
|
||||
node_to_path(Node) ->
|
||||
[(Node)].
|
||||
|
||||
path_to_node(Path) ->
|
||||
case Path of
|
||||
% default slot
|
||||
[Node] -> iolist_to_binary(Node);
|
||||
% handle old possible entries, used when migrating database content to new format
|
||||
[Node | _] when is_binary(Node) ->
|
||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||
% default case (used by PEP for example)
|
||||
_ -> iolist_to_binary(Path)
|
||||
% default slot
|
||||
[Node] -> iolist_to_binary(Node);
|
||||
% handle old possible entries, used when migrating database content to new format
|
||||
[Node | _] when is_binary(Node) ->
|
||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||
% default case (used by PEP for example)
|
||||
_ -> iolist_to_binary(Path)
|
||||
end.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
219
src/node_mb.erl
219
src/node_mb.erl
@ -17,49 +17,41 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Eric Cestari <eric@ohmforce.com>
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_mb).
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('eric@ohmforce.com').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
%%% @doc The module <strong>{@module}</strong> is the pep microblog PubSub plugin.
|
||||
%%% <p> To be used, mod_pubsub must be configured :
|
||||
%%% {mod_pubsub, [ % requires mod_caps
|
||||
%%% {access_createnode, pubsub_createnode},
|
||||
%%% {plugins, ["default", "pep","mb"]},
|
||||
%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]}
|
||||
%%% ]},
|
||||
%%% {access_createnode, pubsub_createnode},
|
||||
%%% {plugins, ["default", "pep","mb"]},
|
||||
%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]}
|
||||
%%% ]},
|
||||
%%% </p>
|
||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
|
||||
|
||||
-module(node_mb).
|
||||
|
||||
-author('eric@ohmforce.com').
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_pep:init(Host, ServerHost, Opts).
|
||||
@ -68,124 +60,127 @@ terminate(Host, ServerHost) ->
|
||||
node_pep:terminate(Host, ServerHost), ok.
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, false},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, presence}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, true}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, false},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, presence},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, true}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, %*
|
||||
<<"auto-create">>, %*
|
||||
<<"auto-subscribe">>, %*
|
||||
<<"delete-nodes">>, %*
|
||||
<<"delete-items">>, %*
|
||||
<<"filtered-notifications">>, %*
|
||||
<<"modify-affiliations">>, <<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>, %*
|
||||
<<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>, %*
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"filtered-notifications">>,
|
||||
<<"modify-affiliations">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_pep:create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_pep:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_pep:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) -> node_pep:delete_node(Removed).
|
||||
delete_node(Removed) ->
|
||||
node_pep:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_pep:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_pep:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_pep:unsubscribe_node(NodeId, Sender, Subscriber,
|
||||
SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_pep:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_pep:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_pep:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_pep:remove_extra_items(NodeId, MaxItems, ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_pep:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_pep:delete_item(NodeId, Publisher, PublishModel,
|
||||
ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_pep:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_pep:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_pep:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_pep:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_pep:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_pep:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_pep:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_pep:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_pep:set_affiliation(NodeId, Owner, Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_pep:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_pep:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_pep:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_pep:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_pep:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_pep:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_pep:set_subscriptions(NodeId, Owner, Subscription,
|
||||
SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_pep:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_pep:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_pep:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_pep:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_pep:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_pep:set_state(State).
|
||||
set_state(State) ->
|
||||
node_pep:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_pep:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_pep:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_pep:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_pep:get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_pep:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_pep:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_pep:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_pep:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_pep:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_pep:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_pep:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_pep:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_pep:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_pep:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_pep:path_to_node(Path).
|
||||
|
559
src/node_pep.erl
559
src/node_pep.erl
@ -17,7 +17,6 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
@ -25,35 +24,29 @@
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_pep).
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
|
||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
|
||||
|
||||
-module(node_pep).
|
||||
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts),
|
||||
@ -63,423 +56,193 @@ init(Host, ServerHost, Opts) ->
|
||||
terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost), ok.
|
||||
|
||||
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, false},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, 1}, {subscribe, true},
|
||||
{access_model, presence}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, true}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, false},
|
||||
{purge_offline, false},
|
||||
{persist_items, false},
|
||||
{max_items, 1},
|
||||
{subscribe, true},
|
||||
{access_model, presence},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, true}].
|
||||
|
||||
-spec(features/0 :: () -> Features::[binary(),...]).
|
||||
features() ->
|
||||
[<<"create-nodes">>, %*
|
||||
<<"auto-create">>, %*
|
||||
<<"auto-subscribe">>, %*
|
||||
<<"delete-nodes">>, %*
|
||||
<<"delete-items">>, %*
|
||||
<<"filtered-notifications">>, %*
|
||||
<<"modify-affiliations">>, <<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>, %*
|
||||
<<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>, %*
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>].
|
||||
|
||||
|
||||
-spec(create_node_permission/6 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPEP(),
|
||||
ServerHost :: binary(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
_ParentNodeId :: mod_pubsub:nodeId(),
|
||||
Owner :: jid(),
|
||||
Access :: atom())
|
||||
-> {result, boolean()}
|
||||
).
|
||||
[<<"create-nodes">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"filtered-notifications">>,
|
||||
<<"modify-affiliations">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
|
||||
LOwner = jlib:jid_tolower(Owner),
|
||||
{User, Server, _Resource} = LOwner,
|
||||
Allowed = case LOwner of
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
_ ->
|
||||
case acl:match_rule(ServerHost, Access, LOwner) of
|
||||
allow ->
|
||||
case Host of
|
||||
{User, Server, _} -> true;
|
||||
_ -> false
|
||||
end;
|
||||
_ ->
|
||||
case acl:match_rule(ServerHost, Access, LOwner) of
|
||||
allow ->
|
||||
case Host of
|
||||
{User, Server, _} -> true;
|
||||
_ -> false
|
||||
end;
|
||||
E -> ?DEBUG("Create not allowed : ~p~n", [E]), false
|
||||
end
|
||||
end,
|
||||
false
|
||||
end
|
||||
end,
|
||||
{result, Allowed}.
|
||||
|
||||
-spec(create_node/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid())
|
||||
-> {result, {default, broadcast}}
|
||||
).
|
||||
create_node(NodeIdx, Owner) ->
|
||||
node_hometree:create_node(NodeIdx, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
-spec(delete_node/1 ::
|
||||
(
|
||||
Nodes :: [mod_pubsub:pubsubNode(),...])
|
||||
-> {result,
|
||||
{[],
|
||||
[{mod_pubsub:pubsubNode(),
|
||||
[{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]},...]},...]
|
||||
}
|
||||
}
|
||||
).
|
||||
delete_node(Nodes) ->
|
||||
{result, {_, _, Result}} = node_hometree:delete_node(Nodes),
|
||||
{result, {[], Result}}.
|
||||
|
||||
delete_node(Removed) ->
|
||||
case node_hometree:delete_node(Removed) of
|
||||
{result, {_, _, Result}} -> {result, {[], Result}};
|
||||
Error -> Error
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
case node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
|
||||
{error, Error} -> {error, Error};
|
||||
{result, _} -> {result, []}
|
||||
end.
|
||||
|
||||
-spec(subscribe_node/8 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: ljid(),
|
||||
AccessModel :: mod_pubsub:accessModel(),
|
||||
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
-> {result, {default, subscribed, mod_pubsub:subId()}}
|
||||
| {result, {default, subscribed, mod_pubsub:subId(), send_last}}
|
||||
| {result, {default, pending, mod_pubsub:subId()}}
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
subscribe_node(NodeIdx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeIdx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
-spec(unsubscribe_node/4 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: ljid(),
|
||||
SubId :: subId())
|
||||
-> {result, default}
|
||||
%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) ->
|
||||
case node_hometree:unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) of
|
||||
{error, Error} -> {error, Error};
|
||||
{result, _} -> {result, []}
|
||||
end.
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
-spec(publish_item/6 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: mod_pubsub:publishModel(),
|
||||
Max_Items :: non_neg_integer(),
|
||||
ItemId :: <<>> | mod_pubsub:itemId(),
|
||||
Payload :: mod_pubsub:payload())
|
||||
-> {result, {default, broadcast, [mod_pubsub:itemId()]}}
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
-spec(remove_extra_items/3 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Max_Items :: unlimited | non_neg_integer(),
|
||||
ItemIds :: [mod_pubsub:itemId()])
|
||||
-> {result,
|
||||
{NewItems::[mod_pubsub:itemId()],
|
||||
OldItems::[mod_pubsub:itemId()]}
|
||||
}
|
||||
).
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
|
||||
-spec(delete_item/4 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: mod_pubsub:publishModel(),
|
||||
ItemId :: <<>> | mod_pubsub:itemId())
|
||||
-> {result, {default, broadcast}}
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
delete_item(NodeIdx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeIdx, Publisher, PublishModel, ItemId).
|
||||
|
||||
-spec(purge_node/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid())
|
||||
-> {result, {default, broadcast}}
|
||||
| {error, xmlel()}
|
||||
).
|
||||
purge_node(NodeIdx, Owner) ->
|
||||
node_hometree:purge_node(NodeIdx, Owner).
|
||||
|
||||
-spec(get_entity_affiliations/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPEP(),
|
||||
Owner :: jid())
|
||||
-> {result, [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]}
|
||||
).
|
||||
get_entity_affiliations(_Host, Owner) ->
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
{_, D, _} = SubKey = jlib:jid_tolower(Owner),
|
||||
SubKey = jlib:jid_tolower(Owner),
|
||||
GenKey = jlib:jid_remove_resource(SubKey),
|
||||
States = mnesia:match_object(#pubsub_state{stateid =
|
||||
{GenKey, '_'},
|
||||
_ = '_'}),
|
||||
NodeTree = case catch
|
||||
ets:lookup(gen_mod:get_module_proc(D, config), nodetree)
|
||||
of
|
||||
[{nodetree, N}] -> N;
|
||||
_ -> nodetree_tree
|
||||
end,
|
||||
Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N},
|
||||
affiliation = A},
|
||||
Acc) ->
|
||||
case NodeTree:get_node(N) of
|
||||
#pubsub_node{nodeid = {{_, D, _}, _}} =
|
||||
Node ->
|
||||
[{Node, A} | Acc];
|
||||
_ -> Acc
|
||||
end
|
||||
end,
|
||||
[], States),
|
||||
States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
|
||||
NodeTree = mod_pubsub:tree(Host),
|
||||
Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) ->
|
||||
case NodeTree:get_node(N) of
|
||||
#pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A} | Acc];
|
||||
_ -> Acc
|
||||
end
|
||||
end,
|
||||
[], States),
|
||||
{result, Reply}.
|
||||
|
||||
|
||||
-spec(get_node_affiliations/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
|
||||
).
|
||||
get_node_affiliations(NodeIdx) ->
|
||||
node_hometree:get_node_affiliations(NodeIdx).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
-spec(get_affiliation/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid())
|
||||
-> {result, mod_pubsub:affiliation()}
|
||||
).
|
||||
get_affiliation(NodeIdx, Owner) ->
|
||||
node_hometree:get_affiliation(NodeIdx, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
-spec(set_affiliation/3 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: ljid(),
|
||||
Affiliation :: mod_pubsub:affiliation())
|
||||
-> ok
|
||||
).
|
||||
set_affiliation(NodeIdx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeIdx, Owner, Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
-spec(get_entity_subscriptions/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPEP(),
|
||||
Owner :: jid())
|
||||
-> {result,
|
||||
[{mod_pubsub:pubsubNode(),
|
||||
mod_pubsub:subscription(),
|
||||
mod_pubsub:subId(),
|
||||
ljid()}]
|
||||
}
|
||||
).
|
||||
get_entity_subscriptions(_Host, Owner) ->
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
{U, D, _} = SubKey = jlib:jid_tolower(Owner),
|
||||
GenKey = jlib:jid_remove_resource(SubKey),
|
||||
States = case SubKey of
|
||||
GenKey ->
|
||||
mnesia:match_object(#pubsub_state{stateid =
|
||||
{{U, D, '_'}, '_'},
|
||||
_ = '_'});
|
||||
_ ->
|
||||
mnesia:match_object(#pubsub_state{stateid =
|
||||
{GenKey, '_'},
|
||||
_ = '_'})
|
||||
++
|
||||
mnesia:match_object(#pubsub_state{stateid =
|
||||
{SubKey, '_'},
|
||||
_ = '_'})
|
||||
end,
|
||||
NodeTree = case catch
|
||||
ets:lookup(gen_mod:get_module_proc(D, config), nodetree)
|
||||
of
|
||||
[{nodetree, N}] -> N;
|
||||
_ -> nodetree_tree
|
||||
end,
|
||||
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N},
|
||||
subscriptions = Ss},
|
||||
Acc) ->
|
||||
case NodeTree:get_node(N) of
|
||||
#pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
|
||||
lists:foldl(fun
|
||||
({subscribed, SubID}, Acc2) ->
|
||||
[{Node, subscribed, SubID, J} | Acc2];
|
||||
({pending, _SubID}, Acc2) ->
|
||||
[{Node, pending, J} | Acc2];
|
||||
(S, Acc2) ->
|
||||
[{Node, S, J} | Acc2]
|
||||
end, Acc, Ss);
|
||||
_ -> Acc
|
||||
end
|
||||
end,
|
||||
[], States),
|
||||
GenKey ->
|
||||
mnesia:match_object(#pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
|
||||
_ ->
|
||||
mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
|
||||
++
|
||||
mnesia:match_object(#pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
|
||||
end,
|
||||
NodeTree = mod_pubsub:tree(Host),
|
||||
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) ->
|
||||
case NodeTree:get_node(N) of
|
||||
#pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
|
||||
lists:foldl(fun
|
||||
({subscribed, SubId}, Acc2) ->
|
||||
[{Node, subscribed, SubId, J} | Acc2];
|
||||
({pending, _SubId}, Acc2) ->
|
||||
[{Node, pending, J} | Acc2];
|
||||
(S, Acc2) ->
|
||||
[{Node, S, J} | Acc2]
|
||||
end,
|
||||
Acc, Ss);
|
||||
_ ->
|
||||
Acc
|
||||
end
|
||||
end,
|
||||
[], States),
|
||||
{result, Reply}.
|
||||
|
||||
-spec(get_node_subscriptions/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> {result,
|
||||
[{ljid(), mod_pubsub:subscription(), mod_pubsub:subId()}] |
|
||||
[{ljid(), none},...]
|
||||
}
|
||||
).
|
||||
get_node_subscriptions(NodeIdx) ->
|
||||
node_hometree:get_node_subscriptions(NodeIdx).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
-spec(get_subscriptions/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: ljid())
|
||||
-> {result, [{mod_pubsub:subscription(), mod_pubsub:subId()}]}
|
||||
).
|
||||
get_subscriptions(NodeIdx, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeIdx, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
-spec(set_subscriptions/4 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid(),
|
||||
Subscription :: mod_pubsub:subscription(),
|
||||
SubId :: mod_pubsub:subId())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
set_subscriptions(NodeIdx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeIdx, Owner, Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
-spec(get_pending_nodes/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
Owner :: jid())
|
||||
-> {result, [mod_pubsub:nodeId()]}
|
||||
).
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
-spec(get_states/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> {result, [mod_pubsub:pubsubState()]}
|
||||
).
|
||||
get_states(NodeIdx) -> node_hometree:get_states(NodeIdx).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
-spec(get_state/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
JID :: ljid())
|
||||
-> mod_pubsub:pubsubState()
|
||||
).
|
||||
get_state(NodeIdx, JID) ->
|
||||
node_hometree:get_state(NodeIdx, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
-spec(set_state/1 ::
|
||||
(
|
||||
State::mod_pubsub:pubsubState())
|
||||
-> ok
|
||||
).
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
-spec(get_items/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
_From :: jid())
|
||||
-> {result, [mod_pubsub:pubsubItem()]}
|
||||
).
|
||||
get_items(NodeIdx, From) ->
|
||||
node_hometree:get_items(NodeIdx, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
-spec(get_items/6 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
JID :: jid(),
|
||||
AccessModel :: mod_pubsub:accessModel(),
|
||||
Presence_Subscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
_SubId :: mod_pubsub:subId())
|
||||
-> {result, [mod_pubsub:pubsubItem()]}
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
-spec(get_item/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
ItemId :: mod_pubsub:itemId())
|
||||
-> {result, mod_pubsub:pubsubItem()}
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_item(NodeIdx, ItemId) ->
|
||||
node_hometree:get_item(NodeIdx, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
-spec(get_item/7 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
ItemId :: mod_pubsub:itemId(),
|
||||
JID :: jid(),
|
||||
AccessModel :: mod_pubsub:accessModel(),
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
SubId :: mod_pubsub:subId())
|
||||
-> {result, mod_pubsub:pubsubItem()}
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup,
|
||||
SubId) ->
|
||||
node_hometree:get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription,
|
||||
RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
-spec(set_item/1 ::
|
||||
(
|
||||
Item::mod_pubsub:pubsubItem())
|
||||
-> ok
|
||||
).
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
||||
%%%
|
||||
%%% Internal
|
||||
@ -491,10 +254,10 @@ path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
%% If not, show a warning message in the ejabberd log file.
|
||||
complain_if_modcaps_disabled(ServerHost) ->
|
||||
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
||||
false ->
|
||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||
"of host ~p. This plugin requires mod_caps "
|
||||
"to be enabled, but it isn't.",
|
||||
[ServerHost]);
|
||||
true -> ok
|
||||
false ->
|
||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||
"of host ~p. This plugin requires mod_caps "
|
||||
"to be enabled, but it isn't.",
|
||||
[ServerHost]);
|
||||
true -> ok
|
||||
end.
|
||||
|
@ -17,7 +17,6 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
@ -25,39 +24,30 @@
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_pep_odbc).
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
|
||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
|
||||
|
||||
-module(node_pep_odbc).
|
||||
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(PUBSUB, mod_pubsub_odbc).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2,
|
||||
get_entity_subscriptions_for_send_last/2,
|
||||
get_node_subscriptions/1, get_subscriptions/2,
|
||||
set_subscriptions/4, get_pending_nodes/2, get_states/1,
|
||||
get_state/2, set_state/1, get_items/7, get_items/6,
|
||||
get_items/3, get_items/2, get_item/7, get_item/2,
|
||||
set_item/1, get_item_name/3, get_last_items/3,
|
||||
node_to_path/1, path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1,
|
||||
get_entity_subscriptions_for_send_last/2, get_last_items/3]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree_odbc:init(Host, ServerHost, Opts),
|
||||
@ -67,362 +57,183 @@ init(Host, ServerHost, Opts) ->
|
||||
terminate(Host, ServerHost) ->
|
||||
node_hometree_odbc:terminate(Host, ServerHost), ok.
|
||||
|
||||
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
|
||||
options() ->
|
||||
[{odbc, true},
|
||||
{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, false},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, 1},
|
||||
{subscribe, true},
|
||||
{access_model, presence},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, on_sub_and_presence},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, true}].
|
||||
[{odbc, true}, {rsm, true} | node_pep:options()].
|
||||
|
||||
-spec(features/0 :: () -> Features::[binary(),...]).
|
||||
features() ->
|
||||
[<<"create-nodes">>, %*
|
||||
<<"auto-create">>, %*
|
||||
<<"auto-subscribe">>, %*
|
||||
<<"delete-nodes">>, %*
|
||||
<<"delete-items">>, %*
|
||||
<<"filtered-notifications">>, %*
|
||||
<<"modify-affiliations">>, <<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>, %*
|
||||
<<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>, %*
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>].
|
||||
[<<"rsm">> | node_pep:features()].
|
||||
|
||||
-spec(create_node_permission/6 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPEP(),
|
||||
ServerHost :: binary(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
_ParentNodeId :: mod_pubsub:nodeId(),
|
||||
Owner :: jid(),
|
||||
Access :: atom())
|
||||
-> {result, boolean()}
|
||||
).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node_permission(Host, ServerHost, _NodeId, _ParentNode, Owner, Access) ->
|
||||
LOwner = jlib:jid_tolower(Owner),
|
||||
{User, Server, _Resource} = LOwner,
|
||||
Allowed = case LOwner of
|
||||
{<<"">>, Host, <<"">>} ->
|
||||
true; % pubsub service always allowed
|
||||
_ ->
|
||||
case acl:match_rule(ServerHost, Access, LOwner) of
|
||||
allow ->
|
||||
case Host of
|
||||
{User, Server, _} -> true;
|
||||
_ -> false
|
||||
end;
|
||||
E -> ?DEBUG("Create not allowed : ~p~n", [E]), false
|
||||
end
|
||||
end,
|
||||
{result, Allowed}.
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree_odbc:create_node(Nidx, Owner),
|
||||
{result, {default, broadcast}}.
|
||||
|
||||
-spec(create_node/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid())
|
||||
-> {result, []}
|
||||
).
|
||||
create_node(NodeIdx, Owner) ->
|
||||
case node_hometree_odbc:create_node(NodeIdx, Owner) of
|
||||
{result, _} -> {result, []};
|
||||
Error -> Error
|
||||
delete_node(Nodes) ->
|
||||
{result, {_, _, Result}} = node_hometree_odbc:delete_node(Nodes),
|
||||
{result, {[], Result}}.
|
||||
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
case node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
|
||||
{error, Error} -> {error, Error};
|
||||
{result, _} -> {result, []}
|
||||
end.
|
||||
|
||||
-spec(delete_node/1 ::
|
||||
(
|
||||
Removed :: [mod_pubsub:pubsubNode(),...])
|
||||
-> {result,
|
||||
{[],
|
||||
[{mod_pubsub:pubsubNode(),
|
||||
[{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]}]}]
|
||||
}
|
||||
}
|
||||
).
|
||||
delete_node(Removed) ->
|
||||
case node_hometree_odbc:delete_node(Removed) of
|
||||
{result, {_, _, Result}} -> {result, {[], Result}};
|
||||
Error -> Error
|
||||
end.
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
-spec(subscribe_node/8 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: ljid(),
|
||||
AccessModel :: mod_pubsub:accessModel(),
|
||||
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
||||
PresenceSubscription :: boolean(),
|
||||
RosterGroup :: boolean(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
-> {result, {default, subscribed, mod_pubsub:subId()}}
|
||||
| {result, {default, subscribed, mod_pubsub:subId(), send_last}}
|
||||
| {result, {default, pending, mod_pubsub:subId()}}
|
||||
%%%
|
||||
| {error, _}
|
||||
| {error, _, binary()}
|
||||
).
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree_odbc:subscribe_node(NodeId, Sender,
|
||||
Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup,
|
||||
Options).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
-spec(unsubscribe_node/4 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Sender :: jid(),
|
||||
Subscriber :: jid(),
|
||||
SubId :: subId())
|
||||
-> {result, []}
|
||||
%
|
||||
| {error, _}
|
||||
| {error, _, binary()}
|
||||
).
|
||||
unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) ->
|
||||
case node_hometree_odbc:unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) of
|
||||
{error, Error} -> {error, Error};
|
||||
{result, _} -> {result, []}
|
||||
end.
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree_odbc:purge_node(Nidx, Owner).
|
||||
|
||||
-spec(publish_item/6 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: mod_pubsub:publishModel(),
|
||||
Max_Items :: non_neg_integer(),
|
||||
ItemId :: <<>> | mod_pubsub:itemId(),
|
||||
Payload :: mod_pubsub:payload())
|
||||
-> {result, {default, broadcast, [mod_pubsub:itemId()]}}
|
||||
%%%
|
||||
| {error, _}
|
||||
).
|
||||
publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree_odbc:publish_item(NodeIdx, Publisher,
|
||||
Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree_odbc:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
|
||||
-spec(delete_item/4 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Publisher :: jid(),
|
||||
PublishModel :: mod_pubsub:publishModel(),
|
||||
ItemId :: <<>> | mod_pubsub:itemId())
|
||||
-> {result, {default, broadcast}}
|
||||
%%%
|
||||
| {error, _}
|
||||
).
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree_odbc:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
|
||||
-spec(purge_node/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: jid())
|
||||
-> {result, {default, broadcast}}
|
||||
| {error, _}
|
||||
).
|
||||
purge_node(NodeIdx, Owner) ->
|
||||
node_hometree_odbc:purge_node(NodeIdx, Owner).
|
||||
|
||||
-spec(get_entity_affiliations/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
Owner :: jid())
|
||||
-> {result, [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]}
|
||||
).
|
||||
get_entity_affiliations(_Host, Owner) ->
|
||||
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner).
|
||||
|
||||
-spec(get_node_affiliations/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
|
||||
).
|
||||
get_node_affiliations(NodeIdx) ->
|
||||
node_hometree_odbc:get_node_affiliations(NodeIdx).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree_odbc:get_node_affiliations(Nidx).
|
||||
|
||||
-spec(get_affiliation/2 ::
|
||||
(
|
||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
||||
Owner :: ljid())
|
||||
-> {result, mod_pubsub:affiliation()}
|
||||
).
|
||||
get_affiliation(NodeIdx, Owner) ->
|
||||
node_hometree_odbc:get_affiliation(NodeIdx, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree_odbc:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree_odbc:set_affiliation(NodeId, Owner, Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(_Host, Owner) ->
|
||||
SubKey = jlib:jid_tolower(Owner),
|
||||
GenKey = jlib:jid_remove_resource(SubKey),
|
||||
Host = (?PUBSUB):escape(element(2, SubKey)),
|
||||
Host = node_hometree_odbc:encode_host(element(2, SubKey)),
|
||||
SJ = node_hometree_odbc:encode_jid(SubKey),
|
||||
GJ = node_hometree_odbc:encode_jid(GenKey),
|
||||
Query = case SubKey of
|
||||
GenKey ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_nod"
|
||||
"e n where i.nodeid = n.nodeid and jid "
|
||||
"like '">>,
|
||||
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||
_ ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_nod"
|
||||
"e n where i.nodeid = n.nodeid and jid "
|
||||
"in ('">>,
|
||||
SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host,
|
||||
<<"';">>]
|
||||
end,
|
||||
GenKey ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_node n "
|
||||
"where i.nodeid = n.nodeid and jid "
|
||||
"like '">>, GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||
_ ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_node n "
|
||||
"where i.nodeid = n.nodeid and jid "
|
||||
"in ('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
|
||||
end,
|
||||
Reply = case catch ejabberd_odbc:sql_query_t(Query) of
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>,
|
||||
<<"jid">>, <<"subscriptions">>],
|
||||
RItems} ->
|
||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||
O = node_hometree_odbc:decode_jid(H),
|
||||
Node = nodetree_tree_odbc:raw_to_node(O,
|
||||
[N,
|
||||
<<"">>,
|
||||
T,
|
||||
I]),
|
||||
{Node,
|
||||
node_hometree_odbc:decode_subscriptions(S),
|
||||
node_hometree_odbc:decode_jid(J)}
|
||||
end,
|
||||
RItems);
|
||||
_ -> []
|
||||
end,
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
|
||||
RItems} ->
|
||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||
O = node_hometree_odbc:decode_jid(H),
|
||||
Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
|
||||
{Node,
|
||||
node_hometree_odbc:decode_subscriptions(S),
|
||||
node_hometree_odbc:decode_jid(J)}
|
||||
end,
|
||||
RItems);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
{result, Reply}.
|
||||
|
||||
get_entity_subscriptions_for_send_last(_Host, Owner) ->
|
||||
SubKey = jlib:jid_tolower(Owner),
|
||||
GenKey = jlib:jid_remove_resource(SubKey),
|
||||
Host = (?PUBSUB):escape(element(2, SubKey)),
|
||||
Host = node_hometree_odbc:encode_host(element(2, SubKey)),
|
||||
SJ = node_hometree_odbc:encode_jid(SubKey),
|
||||
GJ = node_hometree_odbc:encode_jid(GenKey),
|
||||
Query = case SubKey of
|
||||
GenKey ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_nod"
|
||||
"e n, pubsub_node_option o where i.nodeid "
|
||||
"= n.nodeid and n.nodeid = o.nodeid and "
|
||||
"name='send_last_published_item' and "
|
||||
"val='on_sub_and_presence' and jid like "
|
||||
"'">>,
|
||||
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||
_ ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_nod"
|
||||
"e n, pubsub_node_option o where i.nodeid "
|
||||
"= n.nodeid and n.nodeid = o.nodeid and "
|
||||
"name='send_last_published_item' and "
|
||||
"val='on_sub_and_presence' and jid in "
|
||||
"('">>,
|
||||
SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host,
|
||||
<<"';">>]
|
||||
end,
|
||||
GenKey ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_node n, "
|
||||
"pubsub_node_option o where i.nodeid = n.nodeid "
|
||||
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
|
||||
"val='on_sub_and_presence' and jid like '">>,
|
||||
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||
_ ->
|
||||
[<<"select host, node, type, i.nodeid, jid, "
|
||||
"subscriptions from pubsub_state i, pubsub_node n, "
|
||||
"pubsub_node_option o where i.nodeid = n.nodeid "
|
||||
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
|
||||
"val='on_sub_and_presence' and jid in ",
|
||||
"('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
|
||||
end,
|
||||
Reply = case catch ejabberd_odbc:sql_query_t(Query) of
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>,
|
||||
<<"jid">>, <<"subscriptions">>],
|
||||
RItems} ->
|
||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||
O = node_hometree_odbc:decode_jid(H),
|
||||
Node = nodetree_tree_odbc:raw_to_node(O,
|
||||
[N,
|
||||
<<"">>,
|
||||
T,
|
||||
I]),
|
||||
{Node,
|
||||
node_hometree_odbc:decode_subscriptions(S),
|
||||
node_hometree_odbc:decode_jid(J)}
|
||||
end,
|
||||
RItems);
|
||||
_ -> []
|
||||
end,
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
|
||||
RItems} ->
|
||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||
O = node_hometree_odbc:decode_jid(H),
|
||||
Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
|
||||
{Node,
|
||||
node_hometree_odbc:decode_subscriptions(S),
|
||||
node_hometree_odbc:decode_jid(J)}
|
||||
end,
|
||||
RItems);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
{result, Reply}.
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree_odbc:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree_odbc:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree_odbc:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree_odbc:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree_odbc:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) ->
|
||||
node_hometree_odbc:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree_odbc:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree_odbc:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree_odbc:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree_odbc:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree_odbc:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree_odbc:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree_odbc:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, From, RSM) ->
|
||||
node_hometree_odbc:get_items(NodeId, From, RSM).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree_odbc:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, none).
|
||||
get_last_items(Nidx, JID, Count) ->
|
||||
node_hometree_odbc:get_last_items(Nidx, JID, Count).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree_odbc:get_item(Nidx, ItemId).
|
||||
|
||||
get_last_items(NodeId, JID, Count) ->
|
||||
node_hometree_odbc:get_last_items(NodeId, JID, Count).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree_odbc:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree_odbc:get_item(NodeId, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree_odbc:get_item(NodeId, ItemId, JID,
|
||||
AccessModel, PresenceSubscription, RosterGroup,
|
||||
SubId).
|
||||
|
||||
set_item(Item) -> node_hometree_odbc:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree_odbc:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree_odbc:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat_odbc:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat_odbc:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat_odbc:path_to_node(Path).
|
||||
|
||||
%%%
|
||||
%%% Internal
|
||||
@ -433,16 +244,11 @@ path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
|
||||
%% Check that the mod_caps module is enabled in that Jabber Host
|
||||
%% If not, show a warning message in the ejabberd log file.
|
||||
complain_if_modcaps_disabled(ServerHost) ->
|
||||
Modules = ejabberd_config:get_option({modules,
|
||||
ServerHost},
|
||||
fun(Ms) when is_list(Ms) -> Ms end),
|
||||
ModCaps = [mod_caps_enabled
|
||||
|| {mod_caps, _Opts} <- Modules],
|
||||
case ModCaps of
|
||||
[] ->
|
||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||
"of host ~p. This plugin requires mod_caps "
|
||||
"to be enabled, but it isn't.",
|
||||
[ServerHost]);
|
||||
_ -> ok
|
||||
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
||||
false ->
|
||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||
"of host ~p. This plugin requires mod_caps "
|
||||
"to be enabled, but it isn't.",
|
||||
[ServerHost]);
|
||||
true -> ok
|
||||
end.
|
||||
|
@ -17,45 +17,32 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_private).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% Note on function definition
|
||||
%% included is all defined plugin function
|
||||
%% it's possible not to define some function at all
|
||||
%% in that case, warning will be generated at compilation
|
||||
%% and function call will fail,
|
||||
%% then mod_pubsub will call function from node_hometree
|
||||
%% (this makes code cleaner, but execution a little bit longer)
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -64,121 +51,126 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, whitelist}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, false},
|
||||
{presence_based_delivery, false}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, whitelist},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, false},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
||||
<<"delete-items">>, <<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost,
|
||||
Node, ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
@ -17,45 +17,32 @@
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2015, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2015 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(node_public).
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_node).
|
||||
|
||||
%% Note on function definition
|
||||
%% included is all defined plugin function
|
||||
%% it's possible not to define some function at all
|
||||
%% in that case, warning will be generated at compilation
|
||||
%% and function call will fail,
|
||||
%% then mod_pubsub will call function from node_hometree
|
||||
%% (this makes code cleaner, but execution a little bit longer)
|
||||
|
||||
%% API definition
|
||||
-export([init/3, terminate/2, options/0, features/0,
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
create_node_permission/6, create_node/2, delete_node/1,
|
||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||
get_entity_affiliations/2, get_node_affiliations/1,
|
||||
get_affiliation/2, set_affiliation/3,
|
||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||
get_subscriptions/2, set_subscriptions/4,
|
||||
get_pending_nodes/2, get_states/1, get_state/2,
|
||||
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||
path_to_node/1]).
|
||||
|
||||
init(Host, ServerHost, Opts) ->
|
||||
node_hometree:init(Host, ServerHost, Opts).
|
||||
@ -64,123 +51,126 @@ terminate(Host, ServerHost) ->
|
||||
node_hometree:terminate(Host, ServerHost).
|
||||
|
||||
options() ->
|
||||
[{deliver_payloads, true}, {notify_config, false},
|
||||
{notify_delete, false}, {notify_retract, true},
|
||||
{purge_offline, false}, {persist_items, true},
|
||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
||||
{access_model, open}, {roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
[{deliver_payloads, true},
|
||||
{notify_config, false},
|
||||
{notify_delete, false},
|
||||
{notify_retract, true},
|
||||
{purge_offline, false},
|
||||
{persist_items, true},
|
||||
{max_items, ?MAXITEMS},
|
||||
{subscribe, true},
|
||||
{access_model, open},
|
||||
{roster_groups_allowed, []},
|
||||
{publish_model, publishers},
|
||||
{notification_type, headline},
|
||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||
{send_last_published_item, never},
|
||||
{deliver_notifications, true},
|
||||
{presence_based_delivery, false}].
|
||||
|
||||
features() ->
|
||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
||||
<<"delete-items">>, <<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
[<<"create-nodes">>,
|
||||
<<"delete-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>].
|
||||
|
||||
create_node_permission(Host, ServerHost, Node,
|
||||
ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost,
|
||||
Node, ParentNode, Owner, Access).
|
||||
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||
|
||||
create_node(NodeId, Owner) ->
|
||||
node_hometree:create_node(NodeId, Owner).
|
||||
create_node(Nidx, Owner) ->
|
||||
node_hometree:create_node(Nidx, Owner).
|
||||
|
||||
delete_node(Removed) ->
|
||||
node_hometree:delete_node(Removed).
|
||||
|
||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
||||
AccessModel, SendLast, PresenceSubscription,
|
||||
RosterGroup, Options).
|
||||
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||
PresenceSubscription, RosterGroup, Options).
|
||||
|
||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
||||
Subscriber, SubID).
|
||||
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||
|
||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
||||
Payload) ->
|
||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
||||
MaxItems, ItemId, Payload).
|
||||
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||
|
||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
||||
ItemIds).
|
||||
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||
|
||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(NodeId, Publisher,
|
||||
PublishModel, ItemId).
|
||||
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||
|
||||
purge_node(NodeId, Owner) ->
|
||||
node_hometree:purge_node(NodeId, Owner).
|
||||
purge_node(Nidx, Owner) ->
|
||||
node_hometree:purge_node(Nidx, Owner).
|
||||
|
||||
get_entity_affiliations(Host, Owner) ->
|
||||
node_hometree:get_entity_affiliations(Host, Owner).
|
||||
|
||||
get_node_affiliations(NodeId) ->
|
||||
node_hometree:get_node_affiliations(NodeId).
|
||||
get_node_affiliations(Nidx) ->
|
||||
node_hometree:get_node_affiliations(Nidx).
|
||||
|
||||
get_affiliation(NodeId, Owner) ->
|
||||
node_hometree:get_affiliation(NodeId, Owner).
|
||||
get_affiliation(Nidx, Owner) ->
|
||||
node_hometree:get_affiliation(Nidx, Owner).
|
||||
|
||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(NodeId, Owner,
|
||||
Affiliation).
|
||||
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||
|
||||
get_entity_subscriptions(Host, Owner) ->
|
||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||
|
||||
get_node_subscriptions(NodeId) ->
|
||||
node_hometree:get_node_subscriptions(NodeId).
|
||||
get_node_subscriptions(Nidx) ->
|
||||
node_hometree:get_node_subscriptions(Nidx).
|
||||
|
||||
get_subscriptions(NodeId, Owner) ->
|
||||
node_hometree:get_subscriptions(NodeId, Owner).
|
||||
get_subscriptions(Nidx, Owner) ->
|
||||
node_hometree:get_subscriptions(Nidx, Owner).
|
||||
|
||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(NodeId, Owner,
|
||||
Subscription, SubId).
|
||||
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||
|
||||
get_pending_nodes(Host, Owner) ->
|
||||
node_hometree:get_pending_nodes(Host, Owner).
|
||||
|
||||
get_states(NodeId) -> node_hometree:get_states(NodeId).
|
||||
get_states(Nidx) ->
|
||||
node_hometree:get_states(Nidx).
|
||||
|
||||
get_state(NodeId, JID) ->
|
||||
node_hometree:get_state(NodeId, JID).
|
||||
get_state(Nidx, JID) ->
|
||||
node_hometree:get_state(Nidx, JID).
|
||||
|
||||
set_state(State) -> node_hometree:set_state(State).
|
||||
set_state(State) ->
|
||||
node_hometree:set_state(State).
|
||||
|
||||
get_items(NodeId, From) ->
|
||||
node_hometree:get_items(NodeId, From).
|
||||
get_items(Nidx, From, RSM) ->
|
||||
node_hometree:get_items(Nidx, From, RSM).
|
||||
|
||||
get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||
|
||||
get_item(NodeId, ItemId) ->
|
||||
node_hometree:get_item(NodeId, ItemId).
|
||||
get_item(Nidx, ItemId) ->
|
||||
node_hometree:get_item(Nidx, ItemId).
|
||||
|
||||
get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||
PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
set_item(Item) -> node_hometree:set_item(Item).
|
||||
set_item(Item) ->
|
||||
node_hometree:set_item(Item).
|
||||
|
||||
%% @doc <p>Return the name of the node if known: Default is to return
|
||||
%% node id.</p>
|
||||
get_item_name(Host, Node, Id) ->
|
||||
node_hometree:get_item_name(Host, Node, Id).
|
||||
|
||||
node_to_path(Node) -> node_flat:node_to_path(Node).
|
||||
node_to_path(Node) ->
|
||||
node_flat:node_to_path(Node).
|
||||
|
||||
path_to_node(Path) -> node_flat:path_to_node(Path).
|
||||
path_to_node(Path) ->
|
||||
node_flat:path_to_node(Path).
|
||||
|
@ -5,230 +5,154 @@
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%%
|
||||
%%% @author Brian Cully <bjc@kublai.com>
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
-module(nodetree_dag).
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
-author('bjc@kublai.com').
|
||||
|
||||
%% API
|
||||
-export([init/3, terminate/2, options/0, set_node/1,
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
-export([init/3, terminate/2, options/0, set_node/1,
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
|
||||
|
||||
-define(DEFAULT_NODETYPE, leaf).
|
||||
|
||||
-define(DEFAULT_PARENTS, []).
|
||||
|
||||
-define(DEFAULT_CHILDREN, []).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
init(Host, ServerHost, Opts) ->
|
||||
nodetree_tree:init(Host, ServerHost, Opts).
|
||||
|
||||
terminate(Host, ServerHost) ->
|
||||
nodetree_tree:terminate(Host, ServerHost).
|
||||
|
||||
-spec(create_node/6 ::
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId(),
|
||||
Type :: binary(),
|
||||
Owner :: jid(),
|
||||
Options :: mod_pubsub:nodeOptions(),
|
||||
Parents :: [mod_pubsub:nodeId()])
|
||||
-> {ok, NodeIdx::mod_pubsub:nodeIdx()}
|
||||
| {error, xmlel()}
|
||||
).
|
||||
create_node(Key, NodeID, Type, Owner, Options, Parents) ->
|
||||
OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
case find_node(Key, NodeID) of
|
||||
false ->
|
||||
NodeIdx = pubsub_index:new(node),
|
||||
N = #pubsub_node{nodeid = oid(Key, NodeID), id = NodeIdx,
|
||||
type = Type, parents = Parents, owners = [OwnerJID],
|
||||
options = Options},
|
||||
case set_node(N) of
|
||||
ok -> {ok, NodeIdx};
|
||||
Other -> Other
|
||||
end;
|
||||
_ -> {error, ?ERR_CONFLICT}
|
||||
end.
|
||||
|
||||
-spec(set_node/1 ::
|
||||
(
|
||||
PubsubNode::mod_pubsub:pubsubNode())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} =
|
||||
Node) ->
|
||||
set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} = Node) ->
|
||||
Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
|
||||
case validate_parentage(Key, Owners, Parents) of
|
||||
true ->
|
||||
mnesia:write(Node#pubsub_node{parents = Parents});
|
||||
Other -> Other
|
||||
true -> mnesia:write(Node#pubsub_node{parents = Parents});
|
||||
Other -> Other
|
||||
end.
|
||||
|
||||
-spec(delete_node/2 ::
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode(),...]
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
delete_node(Key, NodeID) ->
|
||||
case find_node(Key, NodeID) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
Node ->
|
||||
lists:foreach(fun (#pubsub_node{options = Opts} =
|
||||
Child) ->
|
||||
NewOpts = remove_config_parent(NodeID, Opts),
|
||||
Parents = find_opt(collection, ?DEFAULT_PARENTS,
|
||||
NewOpts),
|
||||
ok = mnesia:write(pubsub_node,
|
||||
Child#pubsub_node{parents =
|
||||
Parents,
|
||||
options =
|
||||
NewOpts},
|
||||
write)
|
||||
end,
|
||||
get_subnodes(Key, NodeID)),
|
||||
pubsub_index:free(node, Node#pubsub_node.id),
|
||||
mnesia:delete_object(pubsub_node, Node, write),
|
||||
[Node]
|
||||
create_node(Key, Node, Type, Owner, Options, Parents) ->
|
||||
OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
case find_node(Key, Node) of
|
||||
false ->
|
||||
Nidx = pubsub_index:new(node),
|
||||
N = #pubsub_node{nodeid = oid(Key, Node), id = Nidx,
|
||||
type = Type, parents = Parents, owners = [OwnerJID],
|
||||
options = Options},
|
||||
case set_node(N) of
|
||||
ok -> {ok, Nidx};
|
||||
Other -> Other
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_CONFLICT}
|
||||
end.
|
||||
|
||||
options() -> nodetree_tree:options().
|
||||
|
||||
get_node(Host, NodeID, _From) -> get_node(Host, NodeID).
|
||||
|
||||
-spec(get_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
%%%
|
||||
| {error, xmlel}
|
||||
).
|
||||
get_node(Host, NodeID) ->
|
||||
case find_node(Host, NodeID) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
Node -> Node
|
||||
delete_node(Key, Node) ->
|
||||
case find_node(Key, Node) of
|
||||
false ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND};
|
||||
Record ->
|
||||
lists:foreach(fun (#pubsub_node{options = Opts} = Child) ->
|
||||
NewOpts = remove_config_parent(Node, Opts),
|
||||
Parents = find_opt(collection, ?DEFAULT_PARENTS, NewOpts),
|
||||
ok = mnesia:write(pubsub_node,
|
||||
Child#pubsub_node{parents = Parents,
|
||||
options = NewOpts},
|
||||
write)
|
||||
end,
|
||||
get_subnodes(Key, Node)),
|
||||
pubsub_index:free(node, Record#pubsub_node.id),
|
||||
mnesia:delete_object(pubsub_node, Record, write),
|
||||
[Record]
|
||||
end.
|
||||
|
||||
-spec(get_node/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_node(NodeId) -> nodetree_tree:get_node(NodeId).
|
||||
options() ->
|
||||
nodetree_tree:options().
|
||||
|
||||
get_node(Host, Node, _From) ->
|
||||
get_node(Host, Node).
|
||||
|
||||
get_node(Host, Node) ->
|
||||
case find_node(Host, Node) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
Record -> Record
|
||||
end.
|
||||
|
||||
get_node(Node) ->
|
||||
nodetree_tree:get_node(Node).
|
||||
|
||||
get_nodes(Key, From) ->
|
||||
nodetree_tree:get_nodes(Key, From).
|
||||
|
||||
-spec(get_nodes/1 ::
|
||||
(
|
||||
Host::mod_pubsub:host())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_nodes(Key) -> nodetree_tree:get_nodes(Key).
|
||||
get_nodes(Key) ->
|
||||
nodetree_tree:get_nodes(Key).
|
||||
|
||||
-spec(get_parentnodes/3 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId(),
|
||||
_From :: _)
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_parentnodes(Host, NodeID, _From) ->
|
||||
case find_node(Host, NodeID) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
#pubsub_node{parents = Parents} ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, NNode}} = N
|
||||
get_parentnodes(Host, Node, _From) ->
|
||||
case find_node(Host, Node) of
|
||||
false ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND};
|
||||
#pubsub_node{parents = Parents} ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, NNode}} = N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Parent <- Parents, Host == NHost, Parent == NNode]),
|
||||
qlc:e(Q)
|
||||
Parent <- Parents, Host == NHost, Parent == NNode]),
|
||||
qlc:e(Q)
|
||||
end.
|
||||
|
||||
get_parentnodes_tree(Host, NodeID, _From) ->
|
||||
Pred = fun (NID, #pubsub_node{nodeid = {_, NNodeID}}) ->
|
||||
NID == NNodeID
|
||||
end,
|
||||
get_parentnodes_tree(Host, Node, _From) ->
|
||||
Pred = fun (NID, #pubsub_node{nodeid = {_, NNode}}) ->
|
||||
NID == NNode
|
||||
end,
|
||||
Tr = fun (#pubsub_node{parents = Parents}) -> Parents
|
||||
end,
|
||||
traversal_helper(Pred, Tr, Host, [NodeID]).
|
||||
end,
|
||||
traversal_helper(Pred, Tr, Host, [Node]).
|
||||
|
||||
get_subnodes(Host, NodeID, _From) ->
|
||||
get_subnodes(Host, NodeID).
|
||||
get_subnodes(Host, Node, _From) ->
|
||||
get_subnodes(Host, Node).
|
||||
|
||||
-spec(get_subnodes/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_subnodes(Host, <<>>) ->
|
||||
get_subnodes_helper(Host, <<>>);
|
||||
get_subnodes(Host, NodeID) ->
|
||||
case find_node(Host, NodeID) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
_ -> get_subnodes_helper(Host, NodeID)
|
||||
get_subnodes(Host, Node) ->
|
||||
case find_node(Host, Node) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
_ -> get_subnodes_helper(Host, Node)
|
||||
end.
|
||||
|
||||
-spec(get_subnodes_helper/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_subnodes_helper(Host, NodeID) ->
|
||||
Q = qlc:q([Node
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
Node
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, lists:member(NodeID, Parents)]),
|
||||
get_subnodes_helper(Host, Node) ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, lists:member(Node, Parents)]),
|
||||
qlc:e(Q).
|
||||
|
||||
get_subnodes_tree(Host, NodeID, From) ->
|
||||
get_subnodes_tree(Host, Node, From) ->
|
||||
Pred = fun (NID, #pubsub_node{parents = Parents}) ->
|
||||
lists:member(NID, Parents)
|
||||
end,
|
||||
lists:member(NID, Parents)
|
||||
end,
|
||||
Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end,
|
||||
traversal_helper(Pred, Tr, 1, Host, [NodeID],
|
||||
[{0, [get_node(Host, NodeID, From)]}]).
|
||||
traversal_helper(Pred, Tr, 1, Host, [Node],
|
||||
[{0, [get_node(Host, Node, From)]}]).
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
@ -236,17 +160,17 @@ get_subnodes_tree(Host, NodeID, From) ->
|
||||
oid(Key, Name) -> {Key, Name}.
|
||||
|
||||
%% Key = jlib:jid() | host()
|
||||
%% NodeID = string()
|
||||
%% Node = string()
|
||||
-spec(find_node/2 ::
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
NodeID :: mod_pubsub:nodeId())
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
Node :: mod_pubsub:nodeId())
|
||||
-> mod_pubsub:pubsubNode() | false
|
||||
).
|
||||
find_node(Key, NodeID) ->
|
||||
case mnesia:read(pubsub_node, oid(Key, NodeID), read) of
|
||||
[] -> false;
|
||||
[Node] -> Node
|
||||
).
|
||||
find_node(Key, Node) ->
|
||||
case mnesia:read(pubsub_node, oid(Key, Node), read) of
|
||||
[] -> false;
|
||||
[Node] -> Node
|
||||
end.
|
||||
|
||||
%% Key = jlib:jid() | host()
|
||||
@ -254,77 +178,67 @@ find_node(Key, NodeID) ->
|
||||
%% Options = [{Key = atom(), Value = term()}]
|
||||
find_opt(Key, Default, Options) ->
|
||||
case lists:keysearch(Key, 1, Options) of
|
||||
{value, {Key, Val}} -> Val;
|
||||
_ -> Default
|
||||
{value, {Key, Val}} -> Val;
|
||||
_ -> Default
|
||||
end.
|
||||
|
||||
-spec(traversal_helper/4 ::
|
||||
(
|
||||
Pred :: fun(),
|
||||
Tr :: fun(),
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
NodeId :: [mod_pubsub:pubsubNode(),...])
|
||||
-> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}]
|
||||
).
|
||||
|
||||
traversal_helper(Pred, Tr, Host, NodeIDs) ->
|
||||
traversal_helper(Pred, Tr, 0, Host, NodeIDs, []).
|
||||
(
|
||||
Pred :: fun(),
|
||||
Tr :: fun(),
|
||||
Host :: mod_pubsub:hostPubsub(),
|
||||
Nodes :: [mod_pubsub:nodeId(),...])
|
||||
-> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}]
|
||||
).
|
||||
traversal_helper(Pred, Tr, Host, Nodes) ->
|
||||
traversal_helper(Pred, Tr, 0, Host, Nodes, []).
|
||||
|
||||
traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) ->
|
||||
Acc;
|
||||
traversal_helper(Pred, Tr, Depth, Host, NodeIDs, Acc) ->
|
||||
Q = qlc:q([Node
|
||||
|| #pubsub_node{nodeid = {NHost, _}} = Node
|
||||
<- mnesia:table(pubsub_node),
|
||||
NodeID <- NodeIDs, Host == NHost, Pred(NodeID, Node)]),
|
||||
traversal_helper(Pred, Tr, Depth, Host, Nodes, Acc) ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, _}} = N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Node <- Nodes, Host == NHost, Pred(Node, N)]),
|
||||
Nodes = qlc:e(Q),
|
||||
IDs = lists:flatmap(Tr, Nodes),
|
||||
traversal_helper(Pred, Tr, Depth + 1, Host, IDs,
|
||||
[{Depth, Nodes} | Acc]).
|
||||
traversal_helper(Pred, Tr, Depth + 1, Host, IDs, [{Depth, Nodes} | Acc]).
|
||||
|
||||
remove_config_parent(NodeID, Options) ->
|
||||
remove_config_parent(NodeID, Options, []).
|
||||
remove_config_parent(Node, Options) ->
|
||||
remove_config_parent(Node, Options, []).
|
||||
|
||||
remove_config_parent(_NodeID, [], Acc) ->
|
||||
remove_config_parent(_Node, [], Acc) ->
|
||||
lists:reverse(Acc);
|
||||
remove_config_parent(NodeID, [{collection, Parents} | T], Acc) ->
|
||||
remove_config_parent(NodeID, T,
|
||||
[{collection, lists:delete(NodeID, Parents)} | Acc]);
|
||||
remove_config_parent(NodeID, [H | T], Acc) ->
|
||||
remove_config_parent(NodeID, T, [H | Acc]).
|
||||
remove_config_parent(Node, [{collection, Parents} | T], Acc) ->
|
||||
remove_config_parent(Node, T, [{collection, lists:delete(Node, Parents)} | Acc]);
|
||||
remove_config_parent(Node, [H | T], Acc) ->
|
||||
remove_config_parent(Node, T, [H | Acc]).
|
||||
|
||||
-spec(validate_parentage/3 ::
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
Owners :: [ljid(),...],
|
||||
Parent_NodeIds :: [mod_pubsub:nodeId()])
|
||||
(
|
||||
Key :: mod_pubsub:hostPubsub(),
|
||||
Owners :: [ljid(),...],
|
||||
Parent_Nodes :: [mod_pubsub:nodeId()])
|
||||
-> true
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
validate_parentage(_Key, _Owners, []) -> true;
|
||||
| {error, xmlel()}
|
||||
).
|
||||
validate_parentage(_Key, _Owners, []) ->
|
||||
true;
|
||||
validate_parentage(Key, Owners, [[] | T]) ->
|
||||
validate_parentage(Key, Owners, T);
|
||||
validate_parentage(Key, Owners, [<<>> | T]) ->
|
||||
validate_parentage(Key, Owners, T);
|
||||
validate_parentage(Key, Owners, [ParentID | T]) ->
|
||||
case find_node(Key, ParentID) of
|
||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||
#pubsub_node{owners = POwners, options = POptions} ->
|
||||
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
|
||||
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
|
||||
case {MutualOwners, NodeType} of
|
||||
{[], _} -> {error, ?ERR_FORBIDDEN};
|
||||
{_, collection} -> validate_parentage(Key, Owners, T);
|
||||
{_, _} -> {error, ?ERR_NOT_ALLOWED}
|
||||
end
|
||||
end.
|
||||
|
||||
%% @spec (Host) -> jid()
|
||||
%% Host = host()
|
||||
%% @doc <p>Generate pubsub service JID.</p>
|
||||
service_jid(Host) ->
|
||||
case Host of
|
||||
{U, S, _} -> jlib:make_jid(U, S, <<>>);
|
||||
_ -> jlib:make_jid(<<>>, Host, <<>>)
|
||||
false ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND};
|
||||
#pubsub_node{owners = POwners, options = POptions} ->
|
||||
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
|
||||
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
|
||||
case {MutualOwners, NodeType} of
|
||||
{[], _} -> {error, ?ERR_FORBIDDEN};
|
||||
{_, collection} -> validate_parentage(Key, Owners, T);
|
||||
{_, _} -> {error, ?ERR_NOT_ALLOWED}
|
||||
end
|
||||
end.
|
||||
|
@ -36,287 +36,163 @@
|
||||
%%% improvements.</p>
|
||||
|
||||
-module(nodetree_tree).
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
|
||||
-export([init/3, terminate/2, options/0, set_node/1,
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
|
||||
%% ================
|
||||
%% API definition
|
||||
%% ================
|
||||
|
||||
%% @spec (Host, ServerHost, Options) -> ok
|
||||
%% Host = string()
|
||||
%% ServerHost = string()
|
||||
%% Options = [{atom(), term()}]
|
||||
%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
|
||||
%% implement this function. It can return anything.</p>
|
||||
%% <p>This function is mainly used to trigger the setup task necessary for the
|
||||
%% plugin. It can be used for example by the developer to create the specific
|
||||
%% module database schema if it does not exists yet.</p>
|
||||
init(_Host, _ServerHost, _Options) ->
|
||||
mnesia:create_table(pubsub_node,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_node)}]),
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_node)}]),
|
||||
mnesia:add_table_index(pubsub_node, id),
|
||||
NodesFields = record_info(fields, pubsub_node),
|
||||
case mnesia:table_info(pubsub_node, attributes) of
|
||||
NodesFields -> ok;
|
||||
_ -> ok
|
||||
NodesFields -> ok;
|
||||
_ -> ok
|
||||
end,
|
||||
%% mnesia:transform_table(pubsub_state, ignore, StatesFields)
|
||||
ok.
|
||||
%% @spec (Host, ServerHost) -> ok
|
||||
%% Host = string()
|
||||
%% ServerHost = string()
|
||||
|
||||
%% @spec () -> Options
|
||||
%% Options = [mod_pubsub:nodeOption()]
|
||||
%% @doc Returns the default pubsub node tree options.
|
||||
terminate(_Host, _ServerHost) -> ok.
|
||||
terminate(_Host, _ServerHost) ->
|
||||
ok.
|
||||
|
||||
options() -> [{virtual_tree, false}].
|
||||
options() ->
|
||||
[{virtual_tree, false}].
|
||||
|
||||
%% @spec (Node) -> ok | {error, Reason}
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% Reason = mod_pubsub:stanzaError()
|
||||
-spec(set_node/1 ::
|
||||
(
|
||||
Node::mod_pubsub:pubsubNode())
|
||||
-> ok
|
||||
).
|
||||
set_node(Node) when is_record(Node, pubsub_node) ->
|
||||
mnesia:write(Node).
|
||||
%set_node(_) -> {error, ?ERR_INTERNAL_SERVER_ERROR}.
|
||||
|
||||
get_node(Host, Node, _From) -> get_node(Host, Node).
|
||||
get_node(Host, Node, _From) ->
|
||||
get_node(Host, Node).
|
||||
|
||||
%% @spec (Host, NodeId) -> Node | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% Reason = mod_pubsub:stanzaError()
|
||||
-spec(get_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_node(Host, NodeId) ->
|
||||
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
[] -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
% Error -> Error
|
||||
get_node(Host, Node) ->
|
||||
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
-spec(get_node/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
| {error, xmlel()}
|
||||
).
|
||||
get_node(NodeIdx) ->
|
||||
case catch mnesia:index_read(pubsub_node, NodeIdx, #pubsub_node.id) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
[] -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
% Error -> Error
|
||||
get_node(Nidx) ->
|
||||
case catch mnesia:index_read(pubsub_node, Nidx, #pubsub_node.id) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
get_nodes(Host, _From) -> get_nodes(Host).
|
||||
get_nodes(Host, _From) ->
|
||||
get_nodes(Host).
|
||||
|
||||
%% @spec (Host) -> Nodes | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Nodes = [mod_pubsub:pubsubNode()]
|
||||
%% Reason = {aborted, atom()}
|
||||
-spec(get_nodes/1 ::
|
||||
(
|
||||
Host::mod_pubsub:host())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_nodes(Host) ->
|
||||
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
|
||||
|
||||
%% @spec (Host, Node, From) -> []
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Default node tree does not handle parents, return empty list.</p>
|
||||
get_parentnodes(_Host, _NodeId, _From) -> [].
|
||||
get_parentnodes(_Host, _Node, _From) ->
|
||||
[].
|
||||
|
||||
%% @spec (Host, NodeId, From) -> [{Depth, Node}] | []
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% Depth = integer()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% @doc <p>Default node tree does not handle parents, return a list
|
||||
%% containing just this node.</p>
|
||||
-spec(get_parentnodes_tree/3 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
From :: jid())
|
||||
-> [{0, [mod_pubsub:pubsubNode(),...]}]
|
||||
).
|
||||
get_parentnodes_tree(Host, NodeId, From) ->
|
||||
case get_node(Host, NodeId, From) of
|
||||
Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
|
||||
_Error -> []
|
||||
get_parentnodes_tree(Host, Node, _From) ->
|
||||
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||
[Record] when is_record(Record, pubsub_node) -> [{0, [Record]}];
|
||||
_ -> []
|
||||
end.
|
||||
|
||||
%% @spec (Host, NodeId, From) -> Nodes
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% Nodes = [mod_pubsub:pubsubNode()]
|
||||
get_subnodes(Host, NodeId, _From) ->
|
||||
get_subnodes(Host, NodeId).
|
||||
get_subnodes(Host, Node, _From) ->
|
||||
get_subnodes(Host, Node).
|
||||
|
||||
-spec(get_subnodes/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_subnodes(Host, <<>>) ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, Parents == []]),
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, Parents == []]),
|
||||
qlc:e(Q);
|
||||
get_subnodes(Host, Node) ->
|
||||
Q = qlc:q([N
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, lists:member(Node, Parents)]),
|
||||
|| #pubsub_node{nodeid = {NHost, _},
|
||||
parents = Parents} =
|
||||
N
|
||||
<- mnesia:table(pubsub_node),
|
||||
Host == NHost, lists:member(Node, Parents)]),
|
||||
qlc:e(Q).
|
||||
|
||||
get_subnodes_tree(Host, Node, _From) ->
|
||||
get_subnodes_tree(Host, Node).
|
||||
|
||||
%% @spec (Host, NodeId) -> Nodes
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% Nodes = [] | [mod_pubsub:pubsubNode()]
|
||||
-spec(get_subnodes_tree/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_subnodes_tree(Host, NodeId) ->
|
||||
case get_node(Host, NodeId) of
|
||||
{error, _} -> [];
|
||||
Rec ->
|
||||
BasePlugin = jlib:binary_to_atom(<<"node_",
|
||||
(Rec#pubsub_node.type)/binary>>),
|
||||
BasePath = BasePlugin:node_to_path(NodeId),
|
||||
mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R,
|
||||
Acc) ->
|
||||
Plugin = jlib:binary_to_atom(<<"node_",
|
||||
(R#pubsub_node.type)/binary>>),
|
||||
Path = Plugin:node_to_path(N),
|
||||
case lists:prefix(BasePath, Path) and (H == Host) of
|
||||
true -> [R | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end,
|
||||
[], pubsub_node)
|
||||
get_subnodes_tree(Host, Node) ->
|
||||
case get_node(Host, Node) of
|
||||
{error, _} ->
|
||||
[];
|
||||
Rec ->
|
||||
BasePlugin = jlib:binary_to_atom(<<"node_",
|
||||
(Rec#pubsub_node.type)/binary>>),
|
||||
BasePath = BasePlugin:node_to_path(Node),
|
||||
mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R, Acc) ->
|
||||
Plugin = jlib:binary_to_atom(<<"node_",
|
||||
(R#pubsub_node.type)/binary>>),
|
||||
Path = Plugin:node_to_path(N),
|
||||
case lists:prefix(BasePath, Path) and (H == Host) of
|
||||
true -> [R | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end,
|
||||
[], pubsub_node)
|
||||
end.
|
||||
|
||||
%% @spec (Host, NodeId, Type, Owner, Options, Parents) ->
|
||||
%% {ok, NodeIdx} | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% Type = mod_pubsub:nodeType()
|
||||
%% Owner = mod_pubsub:jid()
|
||||
%% Options = [mod_pubsub:nodeOption()]
|
||||
%% Parents = [] | [mod_pubsub:nodeId()]
|
||||
%% NodeIdx = mod_pubsub:nodeIdx()
|
||||
%% Reason = mod_pubsub:stanzaError()
|
||||
-spec(create_node/6 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
Type :: binary(),
|
||||
Owner :: jid(),
|
||||
Options :: mod_pubsub:nodeOptions(),
|
||||
Parents :: [mod_pubsub:nodeId()])
|
||||
-> {ok, NodeIdx::mod_pubsub:nodeIdx()}
|
||||
%%%
|
||||
| {error, xmlel()}
|
||||
).
|
||||
create_node(Host, NodeId, Type, Owner, Options, Parents) ->
|
||||
create_node(Host, Node, Type, Owner, Options, Parents) ->
|
||||
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of
|
||||
[] ->
|
||||
ParentExists = case Host of
|
||||
{_U, _S, _R} ->
|
||||
%% This is special case for PEP handling
|
||||
%% PEP does not uses hierarchy
|
||||
true;
|
||||
_ ->
|
||||
case Parents of
|
||||
[] -> true;
|
||||
[Parent | _] ->
|
||||
case catch mnesia:read({pubsub_node,
|
||||
{Host, Parent}})
|
||||
of
|
||||
[#pubsub_node{owners =
|
||||
[{[], Host, []}]}] ->
|
||||
true;
|
||||
[#pubsub_node{owners = Owners}] ->
|
||||
lists:member(BJID, Owners);
|
||||
_ -> false
|
||||
end;
|
||||
_ -> false
|
||||
end
|
||||
end,
|
||||
case ParentExists of
|
||||
true ->
|
||||
NodeIdx = pubsub_index:new(node),
|
||||
mnesia:write(#pubsub_node{nodeid = {Host, NodeId},
|
||||
id = NodeIdx, parents = Parents,
|
||||
type = Type, owners = [BJID],
|
||||
options = Options}),
|
||||
{ok, NodeIdx};
|
||||
false -> {error, ?ERR_FORBIDDEN}
|
||||
end;
|
||||
_ -> {error, ?ERR_CONFLICT}
|
||||
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||
[] ->
|
||||
ParentExists = case Host of
|
||||
{_U, _S, _R} ->
|
||||
%% This is special case for PEP handling
|
||||
%% PEP does not uses hierarchy
|
||||
true;
|
||||
_ ->
|
||||
case Parents of
|
||||
[] ->
|
||||
true;
|
||||
[Parent | _] ->
|
||||
case catch mnesia:read({pubsub_node, {Host, Parent}}) of
|
||||
[#pubsub_node{owners = [{[], Host, []}]}] ->
|
||||
true;
|
||||
[#pubsub_node{owners = Owners}] ->
|
||||
lists:member(BJID, Owners);
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
case ParentExists of
|
||||
true ->
|
||||
Nidx = pubsub_index:new(node),
|
||||
mnesia:write(#pubsub_node{nodeid = {Host, Node},
|
||||
id = Nidx, parents = Parents,
|
||||
type = Type, owners = [BJID],
|
||||
options = Options}),
|
||||
{ok, Nidx};
|
||||
false ->
|
||||
{error, ?ERR_FORBIDDEN}
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_CONFLICT}
|
||||
end.
|
||||
|
||||
%% @spec (Host, NodeId) -> Removed
|
||||
%% Host = mod_pubsub:host()
|
||||
%% NodeId = mod_pubsub:nodeId()
|
||||
%% Removed = [mod_pubsub:pubsubNode()]
|
||||
-spec(delete_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode(),...]
|
||||
).
|
||||
delete_node(Host, NodeId) ->
|
||||
Removed = get_subnodes_tree(Host, NodeId),
|
||||
lists:foreach(fun (#pubsub_node{nodeid = {_, SubNodeId}, id = SubNodeIdx}) ->
|
||||
pubsub_index:free(node, SubNodeIdx),
|
||||
mnesia:delete({pubsub_node, {Host, SubNodeId}})
|
||||
end,
|
||||
Removed),
|
||||
delete_node(Host, Node) ->
|
||||
Removed = get_subnodes_tree(Host, Node),
|
||||
lists:foreach(fun (#pubsub_node{nodeid = {_, SubNode}, id = SubNidx}) ->
|
||||
pubsub_index:free(node, SubNidx),
|
||||
mnesia:delete({pubsub_node, {Host, SubNode}})
|
||||
end,
|
||||
Removed),
|
||||
Removed.
|
||||
|
@ -36,437 +36,280 @@
|
||||
%%% improvements.</p>
|
||||
|
||||
-module(nodetree_tree_odbc).
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(PUBSUB, mod_pubsub_odbc).
|
||||
|
||||
-define(PLUGIN_PREFIX, <<"node_">>).
|
||||
-define(ODBC_SUFFIX, <<"_odbc">>).
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
|
||||
-export([init/3, terminate/2, options/0, set_node/1,
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
|
||||
-export([raw_to_node/2]).
|
||||
|
||||
%% ================
|
||||
%% API definition
|
||||
%% ================
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
ok.
|
||||
|
||||
%% @spec (Host, ServerHost, Opts) -> any()
|
||||
%% Host = mod_pubsub:host()
|
||||
%% ServerHost = host()
|
||||
%% Opts = list()
|
||||
%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
|
||||
%% implement this function. It can return anything.</p>
|
||||
%% <p>This function is mainly used to trigger the setup task necessary for the
|
||||
%% plugin. It can be used for example by the developer to create the specific
|
||||
%% module database schema if it does not exists yet.</p>
|
||||
%% @spec () -> [Option]
|
||||
%% Option = mod_pubsub:nodetreeOption()
|
||||
%% @doc Returns the default pubsub node tree options.
|
||||
%% @spec (Host, Node, From) -> pubsubNode() | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
init(_Host, _ServerHost, _Opts) -> ok.
|
||||
terminate(_Host, _ServerHost) ->
|
||||
ok.
|
||||
|
||||
terminate(_Host, _ServerHost) -> ok.
|
||||
options() ->
|
||||
[{odbc, true} | nodetree_tree:options()].
|
||||
|
||||
options() -> [{virtual_tree, false}, {odbc, true}].
|
||||
set_node(Record) when is_record(Record, pubsub_node) ->
|
||||
{Host, Node} = Record#pubsub_node.nodeid,
|
||||
Parent = case Record#pubsub_node.parents of
|
||||
[] -> <<>>;
|
||||
[First | _] -> First
|
||||
end,
|
||||
Type = Record#pubsub_node.type,
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
P = ejabberd_odbc:escape(Parent),
|
||||
Nidx = case nodeidx(Host, Node) of
|
||||
{result, OldNidx} ->
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_node_option where "
|
||||
"nodeid='">>, OldNidx, <<"';">>]),
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"update pubsub_node set host='">>,
|
||||
H, <<"' node='">>, N,
|
||||
<<"' parent='">>, P,
|
||||
<<"' type='">>, Type,
|
||||
<<"' where nodeid='">>,
|
||||
OldNidx, <<"';">>]),
|
||||
OldNidx;
|
||||
_ ->
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_node(host, node, "
|
||||
"parent, type) values('">>,
|
||||
H, <<"', '">>, N, <<"', '">>, P,
|
||||
<<"', '">>, Type, <<"');">>]),
|
||||
case nodeidx(Host, Node) of
|
||||
{result, NewNidx} -> NewNidx;
|
||||
_ -> none % this should not happen
|
||||
end
|
||||
end,
|
||||
case Nidx of
|
||||
none ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ ->
|
||||
lists:foreach(fun ({Key, Value}) ->
|
||||
SKey = iolist_to_binary(atom_to_list(Key)),
|
||||
SValue = ejabberd_odbc:escape(
|
||||
list_to_binary(
|
||||
lists:flatten(io_lib:fwrite("~p", [Value])))),
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_node_option(nodeid, "
|
||||
"name, val) values('">>,
|
||||
Nidx, <<"', '">>,
|
||||
SKey, <<"', '">>, SValue, <<"');">>])
|
||||
end,
|
||||
Record#pubsub_node.options),
|
||||
{result, Nidx}
|
||||
end.
|
||||
|
||||
get_node(Host, Node, _From) -> get_node(Host, Node).
|
||||
get_node(Host, Node, _From) ->
|
||||
get_node(Host, Node).
|
||||
|
||||
-spec(get_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
| {error, _}
|
||||
).
|
||||
get_node(Host, Node) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(Node),
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and node='">>, N, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
||||
[RItem]} ->
|
||||
raw_to_node(Host, RItem);
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and node='">>, N, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [RItem]} ->
|
||||
raw_to_node(Host, RItem);
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
-spec(get_node/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> mod_pubsub:pubsubNode()
|
||||
| {error, _}
|
||||
).
|
||||
get_node(NodeIdx) ->
|
||||
get_node(Nidx) ->
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from "
|
||||
"pubsub_node where nodeid='">>,
|
||||
NodeIdx, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"parent">>, <<"type">>],
|
||||
[[Host, Node, Parent, Type]]} ->
|
||||
raw_to_node(Host, [Node, Parent, Type, NodeIdx]);
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from "
|
||||
"pubsub_node where nodeid='">>,
|
||||
Nidx, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"host">>, <<"node">>, <<"parent">>, <<"type">>], [[Host, Node, Parent, Type]]} ->
|
||||
raw_to_node(Host, [Node, Parent, Type, Nidx]);
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
%% @spec (Host, From) -> [pubsubNode()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
get_nodes(Host, _From) -> get_nodes(Host).
|
||||
get_nodes(Host, _From) ->
|
||||
get_nodes(Host).
|
||||
|
||||
-spec(get_nodes/1 ::
|
||||
(
|
||||
Host::mod_pubsub:host())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_nodes(Host) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
||||
RItems} ->
|
||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
||||
RItems);
|
||||
_ -> []
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>, H, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||
[raw_to_node(Host, Item) || Item <- RItems];
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason}
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% Depth = integer()
|
||||
%% Record = pubsubNode()
|
||||
%% @doc <p>Default node tree does not handle parents, return empty list.</p>
|
||||
%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason}
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% Depth = integer()
|
||||
%% Record = pubsubNode()
|
||||
get_parentnodes(_Host, _Node, _From) ->
|
||||
[].
|
||||
|
||||
%% @doc <p>Default node tree does not handle parents, return a list
|
||||
%% containing just this node.</p>
|
||||
get_parentnodes(_Host, _Node, _From) -> [].
|
||||
|
||||
-spec(get_parentnodes_tree/3 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
From :: jid())
|
||||
-> [{0, [mod_pubsub:pubsubNode(),...]}]
|
||||
).
|
||||
|
||||
get_parentnodes_tree(Host, Node, From) ->
|
||||
case get_node(Host, Node, From) of
|
||||
N when is_record(N, pubsub_node) -> [{0, [N]}];
|
||||
_Error -> []
|
||||
{error, _} -> [];
|
||||
Record -> [{0, [Record]}]
|
||||
end.
|
||||
|
||||
get_subnodes(Host, Node, _From) ->
|
||||
get_subnodes(Host, Node).
|
||||
|
||||
%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
-spec(get_subnodes/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
get_subnodes(Host, Node) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(Node),
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and parent='">>, N, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
||||
RItems} ->
|
||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
||||
RItems);
|
||||
_ -> []
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and parent='">>, N, <<"';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||
[raw_to_node(Host, Item) || Item <- RItems];
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
get_subnodes_tree(Host, Node, _From) ->
|
||||
get_subnodes_tree(Host, Node).
|
||||
|
||||
%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
-spec(get_subnodes_tree/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
|
||||
get_subnodes_tree(Host, Node) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(Node),
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and node like '">>, N, <<"%';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
||||
RItems} ->
|
||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
||||
RItems);
|
||||
_ -> []
|
||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||
"pubsub_node where host='">>,
|
||||
H, <<"' and node like '">>, N, <<"%';">>])
|
||||
of
|
||||
{selected,
|
||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||
[raw_to_node(Host, Item) || Item <- RItems];
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok | {error, Reason}
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% NodeType = mod_pubsub:nodeType()
|
||||
%% Owner = mod_pubsub:jid()
|
||||
%% Options = list()
|
||||
%% Parents = list()
|
||||
|
||||
-spec(create_node/6 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
Type :: binary(),
|
||||
Owner :: jid(),
|
||||
Options :: mod_pubsub:nodeOptions(),
|
||||
Parents :: [mod_pubsub:nodeId()])
|
||||
-> {ok, NodeIdx::mod_pubsub:nodeIdx()}
|
||||
%%%
|
||||
| {error, _}
|
||||
).
|
||||
|
||||
create_node(Host, Node, Type, Owner, Options, Parents) ->
|
||||
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
case nodeid(Host, Node) of
|
||||
{error, ?ERR_ITEM_NOT_FOUND} ->
|
||||
ParentExists = case Host of
|
||||
{_U, _S, _R} ->
|
||||
%% This is special case for PEP handling
|
||||
%% PEP does not uses hierarchy
|
||||
true;
|
||||
_ ->
|
||||
case Parents of
|
||||
[] -> true;
|
||||
[Parent | _] ->
|
||||
case nodeid(Host, Parent) of
|
||||
{result, PNodeId} ->
|
||||
case nodeowners(PNodeId) of
|
||||
[{<<>>, Host, <<>>}] -> true;
|
||||
Owners ->
|
||||
lists:member(BJID, Owners)
|
||||
end;
|
||||
_ -> false
|
||||
end;
|
||||
_ -> false
|
||||
end
|
||||
end,
|
||||
case ParentExists of
|
||||
true ->
|
||||
case set_node(#pubsub_node{nodeid = {Host, Node},
|
||||
parents = Parents, type = Type,
|
||||
options = Options})
|
||||
case nodeidx(Host, Node) of
|
||||
{error, ?ERR_ITEM_NOT_FOUND} ->
|
||||
ParentExists = case Host of
|
||||
{_U, _S, _R} ->
|
||||
%% This is special case for PEP handling
|
||||
%% PEP does not uses hierarchy
|
||||
true;
|
||||
_ ->
|
||||
case Parents of
|
||||
[] ->
|
||||
true;
|
||||
[Parent | _] ->
|
||||
case nodeidx(Host, Parent) of
|
||||
{result, PNode} ->
|
||||
case nodeowners(PNode) of
|
||||
[{<<>>, Host, <<>>}] -> true;
|
||||
Owners -> lists:member(BJID, Owners)
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
case ParentExists of
|
||||
true ->
|
||||
case set_node(#pubsub_node{nodeid = {Host, Node},
|
||||
parents = Parents, type = Type,
|
||||
options = Options})
|
||||
of
|
||||
{result, NodeId} -> {ok, NodeId};
|
||||
Other -> Other
|
||||
end;
|
||||
false -> {error, ?ERR_FORBIDDEN}
|
||||
end;
|
||||
{result, _} -> {error, ?ERR_CONFLICT};
|
||||
Error -> Error
|
||||
{result, Nidx} -> {ok, Nidx};
|
||||
Other -> Other
|
||||
end;
|
||||
false ->
|
||||
{error, ?ERR_FORBIDDEN}
|
||||
end;
|
||||
{result, _} ->
|
||||
{error, ?ERR_CONFLICT};
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node) -> [mod_pubsub:node()]
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
-spec(delete_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> [mod_pubsub:pubsubNode()]
|
||||
).
|
||||
|
||||
delete_node(Host, Node) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(Node),
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
Removed = get_subnodes_tree(Host, Node),
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
|
||||
H, <<"' and node like '">>, N, <<"%';">>]),
|
||||
catch ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
|
||||
H, <<"' and node like '">>, N, <<"%';">>]),
|
||||
Removed.
|
||||
|
||||
%% helpers
|
||||
-spec(raw_to_node/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
_ :: {NodeId::mod_pubsub:nodeId(),
|
||||
Parent::mod_pubsub:nodeId(),
|
||||
Type::binary(),
|
||||
NodeIdx::mod_pubsub:nodeIdx()})
|
||||
-> mod_pubsub:pubsubNode()
|
||||
).
|
||||
raw_to_node(Host, [Node, Parent, Type, NodeIdx]) ->
|
||||
raw_to_node(Host, [Node, Parent, Type, Nidx]) ->
|
||||
Options = case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option "
|
||||
"where nodeid='">>,
|
||||
NodeIdx, <<"';">>])
|
||||
of
|
||||
{selected, [<<"name">>, <<"val">>], ROptions} ->
|
||||
DbOpts = lists:map(fun ([Key, Value]) ->
|
||||
RKey =
|
||||
jlib:binary_to_atom(Key),
|
||||
Tokens = element(2,
|
||||
erl_scan:string(
|
||||
binary_to_list(<<Value/binary, ".">>))),
|
||||
RValue = element(2,
|
||||
erl_parse:parse_term(Tokens)),
|
||||
{RKey, RValue}
|
||||
end,
|
||||
ROptions),
|
||||
Module =
|
||||
jlib:binary_to_atom(<<(?PLUGIN_PREFIX)/binary,
|
||||
Type/binary,
|
||||
(?ODBC_SUFFIX)/binary>>),
|
||||
StdOpts = Module:options(),
|
||||
lists:foldl(fun ({Key, Value}, Acc) ->
|
||||
lists:keyreplace(Key, 1, Acc,
|
||||
{Key, Value})
|
||||
end,
|
||||
StdOpts, DbOpts);
|
||||
_ -> []
|
||||
end,
|
||||
Parents = case Parent of
|
||||
<<>> -> [];
|
||||
_ -> [Parent]
|
||||
end,
|
||||
#pubsub_node{nodeid =
|
||||
{Host, Node},
|
||||
parents = Parents,
|
||||
id = NodeIdx, type = Type, options = Options}.
|
||||
|
||||
% @spec (NodeRecord) -> ok | {error, Reason}
|
||||
%% Record = mod_pubsub:pubsub_node()
|
||||
-spec(set_node/1 ::
|
||||
(
|
||||
Record::mod_pubsub:pubsubNode())
|
||||
-> {result, NodeIdx::mod_pubsub:nodeIdx()}
|
||||
%%%
|
||||
| {error, _}
|
||||
).
|
||||
set_node(Record) ->
|
||||
{Host, Node} = Record#pubsub_node.nodeid,
|
||||
Parent = case Record#pubsub_node.parents of
|
||||
[] -> <<>>;
|
||||
[First | _] -> First
|
||||
end,
|
||||
Type = Record#pubsub_node.type,
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(Node),
|
||||
P = (?PUBSUB):escape(Parent),
|
||||
NodeIdx = case nodeid(Host, Node) of
|
||||
{result, OldNodeIdx} ->
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_node_option where "
|
||||
"nodeid='">>,
|
||||
OldNodeIdx, <<"';">>]),
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"update pubsub_node set host='">>,
|
||||
H, <<"' node='">>, N,
|
||||
<<"' parent='">>, P,
|
||||
<<"' type='">>, Type,
|
||||
<<"' where nodeid='">>,
|
||||
OldNodeIdx, <<"';">>]),
|
||||
OldNodeIdx;
|
||||
_ ->
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_node(host, node, "
|
||||
"parent, type) values('">>,
|
||||
H, <<"', '">>, N, <<"', '">>, P,
|
||||
<<"', '">>, Type, <<"');">>]),
|
||||
case nodeid(Host, Node) of
|
||||
{result, NewNodeIdx} -> NewNodeIdx;
|
||||
_ -> none % this should not happen
|
||||
end
|
||||
end,
|
||||
case NodeIdx of
|
||||
none -> {error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ ->
|
||||
lists:foreach(fun ({Key, Value}) ->
|
||||
SKey = iolist_to_binary(atom_to_list(Key)),
|
||||
SValue =
|
||||
(?PUBSUB):escape(list_to_binary(lists:flatten(io_lib:fwrite("~p",
|
||||
[Value])))),
|
||||
catch
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_node_option(nodeid, "
|
||||
"name, val) values('">>,
|
||||
NodeIdx, <<"', '">>,
|
||||
SKey, <<"', '">>,
|
||||
SValue, <<"');">>])
|
||||
end,
|
||||
Record#pubsub_node.options),
|
||||
{result, NodeIdx}
|
||||
end.
|
||||
|
||||
-spec(nodeid/2 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId())
|
||||
-> {result, NodeIdx::mod_pubsub:nodeIdx()}
|
||||
%%%
|
||||
| {error, _}
|
||||
).
|
||||
|
||||
nodeid(Host, NodeId) ->
|
||||
H = (?PUBSUB):escape(Host),
|
||||
N = (?PUBSUB):escape(NodeId),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where "
|
||||
"host='">>,
|
||||
H, <<"' and node='">>, N, <<"';">>])
|
||||
of
|
||||
{selected, [<<"nodeid">>], [[NodeIdx]]} ->
|
||||
{result, NodeIdx};
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
-spec(nodeowners/1 ::
|
||||
(
|
||||
NodeIdx::mod_pubsub:nodeIdx())
|
||||
-> Node_Owners::[ljid()]
|
||||
).
|
||||
|
||||
nodeowners(NodeIdx) ->
|
||||
{result, Res} = node_hometree_odbc:get_node_affiliations(NodeIdx),
|
||||
lists:foldl(fun ({LJID, owner}, Acc) -> [LJID | Acc];
|
||||
(_, Acc) -> Acc
|
||||
ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option "
|
||||
"where nodeid='">>, Nidx, <<"';">>])
|
||||
of
|
||||
{selected, [<<"name">>, <<"val">>], ROptions} ->
|
||||
DbOpts = lists:map(fun ([Key, Value]) ->
|
||||
RKey = jlib:binary_to_atom(Key),
|
||||
Tokens = element(2, erl_scan:string(binary_to_list(<<Value/binary, ".">>))),
|
||||
RValue = element(2, erl_parse:parse_term(Tokens)),
|
||||
{RKey, RValue}
|
||||
end,
|
||||
ROptions),
|
||||
Module = jlib:binary_to_atom(<<"node_", Type/binary, "_odbc">>),
|
||||
StdOpts = Module:options(),
|
||||
lists:foldl(fun ({Key, Value}, Acc) ->
|
||||
lists:keyreplace(Key, 1, Acc, {Key, Value})
|
||||
end,
|
||||
[], Res).
|
||||
StdOpts, DbOpts);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
Parents = case Parent of
|
||||
<<>> -> [];
|
||||
_ -> [Parent]
|
||||
end,
|
||||
#pubsub_node{nodeid = {Host, Node},
|
||||
parents = Parents,
|
||||
id = Nidx, type = Type, options = Options}.
|
||||
|
||||
nodeidx(Host, Node) ->
|
||||
H = node_hometree_odbc:encode_host(Host),
|
||||
N = ejabberd_odbc:escape(Node),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where "
|
||||
"host='">>,
|
||||
H, <<"' and node='">>, N, <<"';">>])
|
||||
of
|
||||
{selected, [<<"nodeid">>], [[Nidx]]} ->
|
||||
{result, Nidx};
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
_ ->
|
||||
{error, ?ERR_ITEM_NOT_FOUND}
|
||||
end.
|
||||
|
||||
nodeowners(Nidx) ->
|
||||
{result, Res} = node_hometree_odbc:get_node_affiliations(Nidx),
|
||||
[LJID || {LJID, Aff} <- Res, Aff =:= owner].
|
||||
|
@ -26,143 +26,84 @@
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @doc The module <strong>{@module}</strong> is the PubSub node tree plugin that
|
||||
%%% allow virtual nodes handling.
|
||||
%%% allow virtual nodes handling. This prevent storage of nodes.
|
||||
%%% <p>PubSub node tree plugins are using the {@link gen_nodetree} behaviour.</p>
|
||||
%%% <p>This plugin development is still a work in progress. Due to optimizations in
|
||||
%%% mod_pubsub, this plugin can not work anymore without altering functioning.
|
||||
%%% Please, send us comments, feedback and improvements.</p>
|
||||
|
||||
-module(nodetree_virtual).
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
|
||||
-export([init/3, terminate/2, options/0, set_node/1,
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||
delete_node/2]).
|
||||
|
||||
%% ================
|
||||
%% API definition
|
||||
%% ================
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
ok.
|
||||
|
||||
%% @spec (Host, ServerHost, Opts) -> any()
|
||||
%% Host = mod_pubsub:host()
|
||||
%% ServerHost = host()
|
||||
%% Opts = list()
|
||||
%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
|
||||
%% implement this function. It can return anything.</p>
|
||||
%% <p>This function is mainly used to trigger the setup task necessary for the
|
||||
%% plugin. It can be used for example by the developer to create the specific
|
||||
%% module database schema if it does not exists yet.</p>
|
||||
%% @spec () -> [Option]
|
||||
%% Option = mod_pubsub:nodetreeOption()
|
||||
%% @doc <p>Returns the default pubsub node tree options.</p>
|
||||
%% @spec (NodeRecord) -> ok | {error, Reason}
|
||||
%% NodeRecord = mod_pubsub:pubsub_node()
|
||||
%% @doc <p>No node record is stored on database. Just do nothing.</p>
|
||||
%% @spec (Host, Node, From) -> pubsubNode()
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle a node database. Any node is considered
|
||||
%% as existing. Node record contains default values.</p>
|
||||
init(_Host, _ServerHost, _Opts) -> ok.
|
||||
terminate(_Host, _ServerHost) ->
|
||||
ok.
|
||||
|
||||
terminate(_Host, _ServerHost) -> ok.
|
||||
options() ->
|
||||
[{virtual_tree, true}].
|
||||
|
||||
options() -> [{virtual_tree, true}].
|
||||
set_node(_Node) ->
|
||||
ok.
|
||||
|
||||
set_node(_NodeRecord) -> ok.
|
||||
get_node(Host, Node, _From) ->
|
||||
get_node(Host, Node).
|
||||
|
||||
get_node(Host, Node, _From) -> get_node(Host, Node).
|
||||
get_node(Host, Node) ->
|
||||
get_node(nodeidx(Host, Node)).
|
||||
|
||||
get_node(Host, Node) -> get_node({Host, Node}).
|
||||
get_node(Nidx) ->
|
||||
{Host, Node} = nodeid(Nidx),
|
||||
Record = #pubsub_node{nodeid = Node, id = Nidx},
|
||||
Module = jlib:binary_to_atom(<<"node_", (Record#pubsub_node.type)/binary>>),
|
||||
Record#pubsub_node{owners = [{<<"">>, Host, <<"">>}],
|
||||
options = Module:options()}.
|
||||
|
||||
get_node({Host, _} = NodeId) ->
|
||||
Record = #pubsub_node{nodeid = NodeId, id = NodeId},
|
||||
Module = jlib:binary_to_atom(<<"node_",
|
||||
(Record#pubsub_node.type)/binary>>),
|
||||
Options = Module:options(),
|
||||
Owners = [{<<"">>, Host, <<"">>}],
|
||||
Record#pubsub_node{owners = Owners, options = Options}.
|
||||
get_nodes(Host, _From) ->
|
||||
get_nodes(Host).
|
||||
|
||||
%% @spec (Host, From) -> [pubsubNode()]
|
||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle a node database. Any node is considered
|
||||
%% as existing. Nodes list can not be determined.</p>
|
||||
%% @spec (Host, Node, From) -> [pubsubNode()]
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
|
||||
%% @spec (Host, Node, From) -> [pubsubNode()]
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
|
||||
%% @spec (Host, Node, From) -> [pubsubNode()]
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
|
||||
get_nodes(Host, _From) -> get_nodes(Host).
|
||||
get_nodes(_Host) ->
|
||||
[].
|
||||
|
||||
get_nodes(_Host) -> [].
|
||||
get_parentnodes(_Host, _Node, _From) ->
|
||||
[].
|
||||
|
||||
get_parentnodes(_Host, _Node, _From) -> [].
|
||||
|
||||
-spec(get_parentnodes_tree/3 ::
|
||||
(
|
||||
Host :: mod_pubsub:host(),
|
||||
NodeId :: mod_pubsub:nodeId(),
|
||||
From :: jid())
|
||||
-> [{0, [mod_pubsub:pubsubNode(),...]}]
|
||||
).
|
||||
get_parentnodes_tree(Host, NodeId, From) ->
|
||||
case get_node(Host, NodeId, From) of
|
||||
Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
|
||||
_Error -> []
|
||||
get_parentnodes_tree(Host, Node, From) ->
|
||||
case get_node(Host, Node, From) of
|
||||
Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
|
||||
_Error -> []
|
||||
end.
|
||||
|
||||
get_subnodes(Host, Node, _From) ->
|
||||
get_subnodes(Host, Node).
|
||||
%% @spec (Host, Node, From) -> [pubsubNode()]
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% From = mod_pubsub:jid()
|
||||
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
|
||||
|
||||
get_subnodes(_Host, _Node) -> [].
|
||||
get_subnodes(_Host, _Node) ->
|
||||
[].
|
||||
|
||||
get_subnodes_tree(Host, Node, _From) ->
|
||||
get_subnodes_tree(Host, Node).
|
||||
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% Type = mod_pubsub:nodeType()
|
||||
%% Owner = mod_pubsub:jid()
|
||||
%% Options = list()
|
||||
%% @doc <p>No node record is stored on database. Any valid node
|
||||
%% is considered as already created.</p>
|
||||
%% <p>default allowed nodes: /home/host/user/any/node/name</p>
|
||||
%% @spec (Host, Node) -> [mod_pubsub:node()]
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = mod_pubsub:pubsubNode()
|
||||
%% @doc <p>Virtual node tree does not handle parent/child.
|
||||
%% node deletion just affects the corresponding node.</p>
|
||||
|
||||
get_subnodes_tree(_Host, _Node) -> [].
|
||||
get_subnodes_tree(_Host, _Node) ->
|
||||
[].
|
||||
|
||||
create_node(Host, Node, _Type, _Owner, _Options,
|
||||
_Parents) ->
|
||||
create_node(Host, Node, _Type, _Owner, _Options, _Parents) ->
|
||||
{error, {virtual, {Host, Node}}}.
|
||||
|
||||
delete_node(Host, Node) -> [get_node(Host, Node)].
|
||||
delete_node(Host, Node) ->
|
||||
[get_node(Host, Node)].
|
||||
|
||||
%% internal helper
|
||||
|
||||
nodeidx(Host, Node) -> term_to_binary({Host, Node}).
|
||||
nodeid(Nidx) -> binary_to_term(Nidx).
|
||||
|
@ -26,89 +26,77 @@
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-export([add_subscription/1, read_subscription/1,
|
||||
delete_subscription/1, update_subscription/1]).
|
||||
delete_subscription/1, update_subscription/1]).
|
||||
|
||||
%% TODO: Those -spec lines produce errors in old Erlang versions.
|
||||
%% They can be enabled again in ejabberd 3.0 because it uses R12B or higher.
|
||||
%% -spec read_subscription(SubID :: string()) -> {ok, #pubsub_subscription{}} | notfound.
|
||||
read_subscription(SubID) ->
|
||||
case
|
||||
ejabberd_odbc:sql_query_t([<<"select opt_name, opt_value from pubsub_subscr"
|
||||
"iption_opt where subid = '">>,
|
||||
ejabberd_odbc:escape(SubID), <<"'">>])
|
||||
of
|
||||
{selected, [<<"opt_name">>, <<"opt_value">>], []} ->
|
||||
notfound;
|
||||
{selected, [<<"opt_name">>, <<"opt_value">>],
|
||||
Options} ->
|
||||
{ok,
|
||||
#pubsub_subscription{subid = SubID,
|
||||
options =
|
||||
lists:map(fun subscription_opt_from_odbc/1,
|
||||
Options)}}
|
||||
ejabberd_odbc:sql_query_t([<<"select opt_name, opt_value from pubsub_subscr"
|
||||
"iption_opt where subid = '">>,
|
||||
ejabberd_odbc:escape(SubID), <<"'">>])
|
||||
of
|
||||
{selected, [<<"opt_name">>, <<"opt_value">>], []} ->
|
||||
notfound;
|
||||
{selected, [<<"opt_name">>, <<"opt_value">>], Options} ->
|
||||
{ok,
|
||||
#pubsub_subscription{subid = SubID,
|
||||
options = lists:map(fun subscription_opt_from_odbc/1, Options)}}
|
||||
end.
|
||||
|
||||
%% -spec delete_subscription(SubID :: string()) -> ok.
|
||||
delete_subscription(SubID) ->
|
||||
%% -spec update_subscription(#pubsub_subscription{}) -> ok .
|
||||
%% -spec add_subscription(#pubsub_subscription{}) -> ok.
|
||||
%% -------------- Internal utilities -----------------------
|
||||
%% -spec update_subscription(#pubsub_subscription{}) -> ok .
|
||||
%% -spec add_subscription(#pubsub_subscription{}) -> ok.
|
||||
%% -------------- Internal utilities -----------------------
|
||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_subscription_opt "
|
||||
"where subid = '">>,
|
||||
ejabberd_odbc:escape(SubID), <<"'">>]),
|
||||
"where subid = '">>,
|
||||
ejabberd_odbc:escape(SubID), <<"'">>]),
|
||||
ok.
|
||||
|
||||
update_subscription(#pubsub_subscription{subid =
|
||||
SubId} =
|
||||
Sub) ->
|
||||
update_subscription(#pubsub_subscription{subid = SubId} = Sub) ->
|
||||
delete_subscription(SubId), add_subscription(Sub).
|
||||
|
||||
add_subscription(#pubsub_subscription{subid = SubId,
|
||||
options = Opts}) ->
|
||||
add_subscription(#pubsub_subscription{subid = SubId, options = Opts}) ->
|
||||
EscapedSubId = ejabberd_odbc:escape(SubId),
|
||||
lists:foreach(fun (Opt) ->
|
||||
{OdbcOptName, OdbcOptValue} =
|
||||
subscription_opt_to_odbc(Opt),
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, "
|
||||
"opt_name, opt_value)values ('">>,
|
||||
EscapedSubId, <<"','">>,
|
||||
OdbcOptName, <<"','">>,
|
||||
OdbcOptValue, <<"')">>])
|
||||
end,
|
||||
Opts),
|
||||
{OdbcOptName, OdbcOptValue} = subscription_opt_to_odbc(Opt),
|
||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, "
|
||||
"opt_name, opt_value)values ('">>,
|
||||
EscapedSubId, <<"','">>,
|
||||
OdbcOptName, <<"','">>,
|
||||
OdbcOptValue, <<"')">>])
|
||||
end,
|
||||
Opts),
|
||||
ok.
|
||||
|
||||
subscription_opt_from_odbc({<<"DELIVER">>, Value}) ->
|
||||
{deliver, odbc_to_boolean(Value)};
|
||||
subscription_opt_from_odbc({<<"DIGEST">>, Value}) ->
|
||||
{digest, odbc_to_boolean(Value)};
|
||||
subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>,
|
||||
Value}) ->
|
||||
subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>, Value}) ->
|
||||
{digest_frequency, odbc_to_integer(Value)};
|
||||
subscription_opt_from_odbc({<<"EXPIRE">>, Value}) ->
|
||||
{expire, odbc_to_timestamp(Value)};
|
||||
subscription_opt_from_odbc({<<"INCLUDE_BODY">>,
|
||||
Value}) ->
|
||||
subscription_opt_from_odbc({<<"INCLUDE_BODY">>, Value}) ->
|
||||
{include_body, odbc_to_boolean(Value)};
|
||||
%%TODO: might be > than 1 show_values value??.
|
||||
%% need to use compact all in only 1 opt.
|
||||
subscription_opt_from_odbc({<<"SHOW_VALUES">>,
|
||||
Value}) ->
|
||||
subscription_opt_from_odbc({<<"SHOW_VALUES">>, Value}) ->
|
||||
{show_values, Value};
|
||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>,
|
||||
Value}) ->
|
||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>, Value}) ->
|
||||
{subscription_type,
|
||||
case Value of
|
||||
<<"items">> -> items;
|
||||
<<"nodes">> -> nodes
|
||||
end};
|
||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>,
|
||||
Value}) ->
|
||||
case Value of
|
||||
<<"items">> -> items;
|
||||
<<"nodes">> -> nodes
|
||||
end};
|
||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>, Value}) ->
|
||||
{subscription_depth,
|
||||
case Value of
|
||||
<<"all">> -> all;
|
||||
N -> odbc_to_integer(N)
|
||||
end}.
|
||||
case Value of
|
||||
<<"all">> -> all;
|
||||
N -> odbc_to_integer(N)
|
||||
end}.
|
||||
|
||||
subscription_opt_to_odbc({deliver, Bool}) ->
|
||||
{<<"DELIVER">>, boolean_to_odbc(Bool)};
|
||||
@ -124,19 +112,18 @@ subscription_opt_to_odbc({show_values, Values}) ->
|
||||
{<<"SHOW_VALUES">>, Values};
|
||||
subscription_opt_to_odbc({subscription_type, Type}) ->
|
||||
{<<"SUBSCRIPTION_TYPE">>,
|
||||
case Type of
|
||||
items -> <<"items">>;
|
||||
nodes -> <<"nodes">>
|
||||
end};
|
||||
case Type of
|
||||
items -> <<"items">>;
|
||||
nodes -> <<"nodes">>
|
||||
end};
|
||||
subscription_opt_to_odbc({subscription_depth, Depth}) ->
|
||||
{<<"SUBSCRIPTION_DEPTH">>,
|
||||
case Depth of
|
||||
all -> <<"all">>;
|
||||
N -> integer_to_odbc(N)
|
||||
end}.
|
||||
case Depth of
|
||||
all -> <<"all">>;
|
||||
N -> integer_to_odbc(N)
|
||||
end}.
|
||||
|
||||
integer_to_odbc(N) ->
|
||||
iolist_to_binary(integer_to_list(N)).
|
||||
integer_to_odbc(N) -> iolist_to_binary(integer_to_list(N)).
|
||||
|
||||
boolean_to_odbc(true) -> <<"1">>;
|
||||
boolean_to_odbc(false) -> <<"0">>.
|
||||
@ -147,5 +134,4 @@ odbc_to_integer(N) -> jlib:binary_to_integer(N).
|
||||
|
||||
odbc_to_boolean(B) -> B == <<"1">>.
|
||||
|
||||
odbc_to_timestamp(T) ->
|
||||
jlib:datetime_string_to_timestamp(T).
|
||||
odbc_to_timestamp(T) -> jlib:datetime_string_to_timestamp(T).
|
||||
|
@ -29,7 +29,6 @@
|
||||
%% new/1 and free/2 MUST be called inside a transaction bloc
|
||||
|
||||
-module(pubsub_index).
|
||||
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
@ -38,30 +37,30 @@
|
||||
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
mnesia:create_table(pubsub_index,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_index)}]).
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_index)}]).
|
||||
|
||||
new(Index) ->
|
||||
case mnesia:read({pubsub_index, Index}) of
|
||||
[I] ->
|
||||
case I#pubsub_index.free of
|
||||
[] ->
|
||||
Id = I#pubsub_index.last + 1,
|
||||
mnesia:write(I#pubsub_index{last = Id}),
|
||||
Id;
|
||||
[Id | Free] ->
|
||||
mnesia:write(I#pubsub_index{free = Free}), Id
|
||||
end;
|
||||
_ ->
|
||||
mnesia:write(#pubsub_index{index = Index, last = 1,
|
||||
free = []}),
|
||||
1
|
||||
[I] ->
|
||||
case I#pubsub_index.free of
|
||||
[] ->
|
||||
Id = I#pubsub_index.last + 1,
|
||||
mnesia:write(I#pubsub_index{last = Id}),
|
||||
Id;
|
||||
[Id | Free] ->
|
||||
mnesia:write(I#pubsub_index{free = Free}), Id
|
||||
end;
|
||||
_ ->
|
||||
mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
|
||||
1
|
||||
end.
|
||||
|
||||
free(Index, Id) ->
|
||||
case mnesia:read({pubsub_index, Index}) of
|
||||
[I] ->
|
||||
Free = I#pubsub_index.free,
|
||||
mnesia:write(I#pubsub_index{free = [Id | Free]});
|
||||
_ -> ok
|
||||
[I] ->
|
||||
Free = I#pubsub_index.free,
|
||||
mnesia:write(I#pubsub_index{free = [Id | Free]});
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
422
src/pubsub_migrate.erl
Normal file
422
src/pubsub_migrate.erl
Normal file
@ -0,0 +1,422 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : pubsub_migrate.erl
|
||||
%%% Author : Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% Purpose : Migration/Upgrade code put out of mod_pubsub
|
||||
%%% Created : 26 Jul 2014 by Christophe Romain <christophe.romain@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2015 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(pubsub_migrate).
|
||||
|
||||
-include("pubsub.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-export([update_node_database/2, update_state_database/2, update_lastitem_database/2]).
|
||||
|
||||
update_item_database_binary() ->
|
||||
F = fun () ->
|
||||
case catch mnesia:read({pubsub_last_item, mnesia:first(pubsub_last_item)}) of
|
||||
[First] when is_list(First#pubsub_last_item.itemid) ->
|
||||
?INFO_MSG("Binarization of pubsub items table...", []),
|
||||
lists:foreach(fun (Id) ->
|
||||
[Node] = mnesia:read({pubsub_last_item, Id}),
|
||||
|
||||
ItemId = iolist_to_binary(Node#pubsub_last_item.itemid),
|
||||
|
||||
ok = mnesia:delete({pubsub_last_item, Id}),
|
||||
ok = mnesia:write(Node#pubsub_last_item{itemid=ItemId})
|
||||
end,
|
||||
mnesia:all_keys(pubsub_last_item));
|
||||
_-> no_need
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Failed to binarize pubsub items table: ~p", [Reason]);
|
||||
{atomic, no_need} ->
|
||||
ok;
|
||||
{atomic, Result} ->
|
||||
?INFO_MSG("Pubsub items table has been binarized: ~p", [Result])
|
||||
end.
|
||||
|
||||
|
||||
update_node_database_binary() ->
|
||||
F = fun () ->
|
||||
case catch mnesia:read({pubsub_node, mnesia:first(pubsub_node)}) of
|
||||
[First] when is_list(First#pubsub_node.type) ->
|
||||
?INFO_MSG("Binarization of pubsub nodes table...", []),
|
||||
lists:foreach(fun ({H, N}) ->
|
||||
[Node] = mnesia:read({pubsub_node, {H, N}}),
|
||||
|
||||
Type = iolist_to_binary(Node#pubsub_node.type),
|
||||
BN = case N of
|
||||
Binary when is_binary(Binary) ->
|
||||
N;
|
||||
_ ->
|
||||
{result, BN1} = mod_pubsub:node_call(H, Type, path_to_node, [N]),
|
||||
BN1
|
||||
end,
|
||||
BP = case [case P of
|
||||
Binary2 when is_binary(Binary2) -> P;
|
||||
_ -> element(2, mod_pubsub:node_call(H, Type, path_to_node, [P]))
|
||||
end
|
||||
|| P <- Node#pubsub_node.parents] of
|
||||
[<<>>] -> [];
|
||||
Parents -> Parents
|
||||
end,
|
||||
|
||||
BH = case H of
|
||||
{U, S, R} -> {iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)};
|
||||
String -> iolist_to_binary(String)
|
||||
end,
|
||||
|
||||
Owners = [{iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)} ||
|
||||
{U, S, R} <- Node#pubsub_node.owners],
|
||||
|
||||
ok = mnesia:delete({pubsub_node, {H, N}}),
|
||||
ok = mnesia:write(Node#pubsub_node{nodeid = {BH, BN},
|
||||
parents = BP,
|
||||
type = Type,
|
||||
owners = Owners});
|
||||
(_) -> ok
|
||||
end,
|
||||
mnesia:all_keys(pubsub_node));
|
||||
_-> no_need
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Failed to binarize pubsub node table: ~p", [Reason]);
|
||||
{atomic, no_need} ->
|
||||
ok;
|
||||
{atomic, Result} ->
|
||||
?INFO_MSG("Pubsub nodes table has been binarized: ~p", [Result])
|
||||
end.
|
||||
|
||||
update_node_database(Host, ServerHost) ->
|
||||
mnesia:del_table_index(pubsub_node, type),
|
||||
mnesia:del_table_index(pubsub_node, parentid),
|
||||
case catch mnesia:table_info(pubsub_node, attributes) of
|
||||
[host_node, host_parent, info] ->
|
||||
?INFO_MSG("Upgrading pubsub nodes table...", []),
|
||||
F = fun () ->
|
||||
{Result, LastIdx} = lists:foldl(fun ({pubsub_node,
|
||||
NodeId, ParentId,
|
||||
{nodeinfo, Items,
|
||||
Options,
|
||||
Entities}},
|
||||
{RecList,
|
||||
NodeIdx}) ->
|
||||
ItemsList =
|
||||
lists:foldl(fun
|
||||
({item,
|
||||
IID,
|
||||
Publisher,
|
||||
Payload},
|
||||
Acc) ->
|
||||
C =
|
||||
{unknown,
|
||||
Publisher},
|
||||
M =
|
||||
{now(),
|
||||
Publisher},
|
||||
mnesia:write(#pubsub_item{itemid
|
||||
=
|
||||
{IID,
|
||||
NodeIdx},
|
||||
creation
|
||||
=
|
||||
C,
|
||||
modification
|
||||
=
|
||||
M,
|
||||
payload
|
||||
=
|
||||
Payload}),
|
||||
[{Publisher,
|
||||
IID}
|
||||
| Acc]
|
||||
end,
|
||||
[],
|
||||
Items),
|
||||
Owners =
|
||||
dict:fold(fun
|
||||
(JID,
|
||||
{entity,
|
||||
Aff,
|
||||
Sub},
|
||||
Acc) ->
|
||||
UsrItems =
|
||||
lists:foldl(fun
|
||||
({P,
|
||||
I},
|
||||
IAcc) ->
|
||||
case
|
||||
P
|
||||
of
|
||||
JID ->
|
||||
[I
|
||||
| IAcc];
|
||||
_ ->
|
||||
IAcc
|
||||
end
|
||||
end,
|
||||
[],
|
||||
ItemsList),
|
||||
mnesia:write({pubsub_state,
|
||||
{JID,
|
||||
NodeIdx},
|
||||
UsrItems,
|
||||
Aff,
|
||||
Sub}),
|
||||
case
|
||||
Aff
|
||||
of
|
||||
owner ->
|
||||
[JID
|
||||
| Acc];
|
||||
_ ->
|
||||
Acc
|
||||
end
|
||||
end,
|
||||
[],
|
||||
Entities),
|
||||
mnesia:delete({pubsub_node,
|
||||
NodeId}),
|
||||
{[#pubsub_node{nodeid
|
||||
=
|
||||
NodeId,
|
||||
id
|
||||
=
|
||||
NodeIdx,
|
||||
parents
|
||||
=
|
||||
[element(2,
|
||||
ParentId)],
|
||||
owners
|
||||
=
|
||||
Owners,
|
||||
options
|
||||
=
|
||||
Options}
|
||||
| RecList],
|
||||
NodeIdx + 1}
|
||||
end,
|
||||
{[], 1},
|
||||
mnesia:match_object({pubsub_node,
|
||||
{Host,
|
||||
'_'},
|
||||
'_',
|
||||
'_'})),
|
||||
mnesia:write(#pubsub_index{index = node, last = LastIdx,
|
||||
free = []}),
|
||||
Result
|
||||
end,
|
||||
{atomic, NewRecords} = mnesia:transaction(F),
|
||||
{atomic, ok} = mnesia:delete_table(pubsub_node),
|
||||
{atomic, ok} = mnesia:create_table(pubsub_node,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes,
|
||||
record_info(fields,
|
||||
pubsub_node)}]),
|
||||
FNew = fun () ->
|
||||
lists:foreach(fun (Record) -> mnesia:write(Record) end,
|
||||
NewRecords)
|
||||
end,
|
||||
case mnesia:transaction(FNew) of
|
||||
{atomic, Result} ->
|
||||
?INFO_MSG("Pubsub nodes table upgraded: ~p",
|
||||
[Result]);
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Problem upgrading Pubsub nodes table:~n~p",
|
||||
[Reason])
|
||||
end;
|
||||
[nodeid, parentid, type, owners, options] ->
|
||||
F = fun ({pubsub_node, NodeId, {_, Parent}, Type,
|
||||
Owners, Options}) ->
|
||||
#pubsub_node{nodeid = NodeId, id = 0,
|
||||
parents = [Parent], type = Type,
|
||||
owners = Owners, options = Options}
|
||||
end,
|
||||
mnesia:transform_table(pubsub_node, F,
|
||||
[nodeid, id, parents, type, owners, options]),
|
||||
FNew = fun () ->
|
||||
LastIdx = lists:foldl(fun (#pubsub_node{nodeid =
|
||||
NodeId} =
|
||||
PubsubNode,
|
||||
NodeIdx) ->
|
||||
mnesia:write(PubsubNode#pubsub_node{id
|
||||
=
|
||||
NodeIdx}),
|
||||
lists:foreach(fun
|
||||
(#pubsub_state{stateid
|
||||
=
|
||||
StateId} =
|
||||
State) ->
|
||||
{JID,
|
||||
_} =
|
||||
StateId,
|
||||
mnesia:delete({pubsub_state,
|
||||
StateId}),
|
||||
mnesia:write(State#pubsub_state{stateid
|
||||
=
|
||||
{JID,
|
||||
NodeIdx}})
|
||||
end,
|
||||
mnesia:match_object(#pubsub_state{stateid
|
||||
=
|
||||
{'_',
|
||||
NodeId},
|
||||
_
|
||||
=
|
||||
'_'})),
|
||||
lists:foreach(fun
|
||||
(#pubsub_item{itemid
|
||||
=
|
||||
ItemId} =
|
||||
Item) ->
|
||||
{IID,
|
||||
_} =
|
||||
ItemId,
|
||||
{M1,
|
||||
M2} =
|
||||
Item#pubsub_item.modification,
|
||||
{C1,
|
||||
C2} =
|
||||
Item#pubsub_item.creation,
|
||||
mnesia:delete({pubsub_item,
|
||||
ItemId}),
|
||||
mnesia:write(Item#pubsub_item{itemid
|
||||
=
|
||||
{IID,
|
||||
NodeIdx},
|
||||
modification
|
||||
=
|
||||
{M2,
|
||||
M1},
|
||||
creation
|
||||
=
|
||||
{C2,
|
||||
C1}})
|
||||
end,
|
||||
mnesia:match_object(#pubsub_item{itemid
|
||||
=
|
||||
{'_',
|
||||
NodeId},
|
||||
_
|
||||
=
|
||||
'_'})),
|
||||
NodeIdx + 1
|
||||
end,
|
||||
1,
|
||||
mnesia:match_object({pubsub_node,
|
||||
{Host, '_'},
|
||||
'_', '_',
|
||||
'_', '_',
|
||||
'_'})
|
||||
++
|
||||
mnesia:match_object({pubsub_node,
|
||||
{{'_',
|
||||
ServerHost,
|
||||
'_'},
|
||||
'_'},
|
||||
'_', '_',
|
||||
'_', '_',
|
||||
'_'})),
|
||||
mnesia:write(#pubsub_index{index = node,
|
||||
last = LastIdx, free = []})
|
||||
end,
|
||||
case mnesia:transaction(FNew) of
|
||||
{atomic, Result} ->
|
||||
rename_default_nodeplugin(),
|
||||
?INFO_MSG("Pubsub nodes table upgraded: ~p",
|
||||
[Result]);
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Problem upgrading Pubsub nodes table:~n~p",
|
||||
[Reason])
|
||||
end;
|
||||
[nodeid, id, parent, type, owners, options] ->
|
||||
F = fun ({pubsub_node, NodeId, Id, Parent, Type, Owners,
|
||||
Options}) ->
|
||||
#pubsub_node{nodeid = NodeId, id = Id,
|
||||
parents = [Parent], type = Type,
|
||||
owners = Owners, options = Options}
|
||||
end,
|
||||
mnesia:transform_table(pubsub_node, F,
|
||||
[nodeid, id, parents, type, owners, options]),
|
||||
rename_default_nodeplugin();
|
||||
_ -> ok
|
||||
end,
|
||||
update_node_database_binary().
|
||||
|
||||
rename_default_nodeplugin() ->
|
||||
lists:foreach(fun (Node) ->
|
||||
mnesia:dirty_write(Node#pubsub_node{type =
|
||||
<<"hometree">>})
|
||||
end,
|
||||
mnesia:dirty_match_object(#pubsub_node{type =
|
||||
<<"default">>,
|
||||
_ = '_'})).
|
||||
|
||||
update_state_database(_Host, _ServerHost) ->
|
||||
case catch mnesia:table_info(pubsub_state, attributes) of
|
||||
[stateid, nodeidx, items, affiliation, subscriptions] ->
|
||||
?INFO_MSG("Upgrading pubsub states table...", []),
|
||||
F = fun ({pubsub_state, {{U,S,R}, NodeID}, _NodeIdx, Items, Aff, Sub}, Acc) ->
|
||||
JID = {iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)},
|
||||
Subs = case Sub of
|
||||
none ->
|
||||
[];
|
||||
[] ->
|
||||
[];
|
||||
_ ->
|
||||
{result, SubID} = pubsub_subscription:subscribe_node(JID, NodeID, []),
|
||||
[{Sub, SubID}]
|
||||
end,
|
||||
NewState = #pubsub_state{stateid = {JID, NodeID},
|
||||
items = Items,
|
||||
affiliation = Aff,
|
||||
subscriptions = Subs},
|
||||
[NewState | Acc]
|
||||
end,
|
||||
{atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3,
|
||||
[F, [], pubsub_state]),
|
||||
{atomic, ok} = mnesia:delete_table(pubsub_state),
|
||||
{atomic, ok} = mnesia:create_table(pubsub_state,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_state)}]),
|
||||
FNew = fun () ->
|
||||
lists:foreach(fun mnesia:write/1, NewRecs)
|
||||
end,
|
||||
case mnesia:transaction(FNew) of
|
||||
{atomic, Result} ->
|
||||
?INFO_MSG("Pubsub states table upgraded: ~p",
|
||||
[Result]);
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Problem upgrading Pubsub states table:~n~p",
|
||||
[Reason])
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
update_lastitem_database(_Host, _ServerHost) ->
|
||||
update_item_database_binary().
|
@ -26,169 +26,111 @@
|
||||
|
||||
%% API
|
||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
||||
get_subscription/3, set_subscription/4,
|
||||
get_options_xform/2, parse_options_xform/1]).
|
||||
get_subscription/3, set_subscription/4,
|
||||
get_options_xform/2, parse_options_xform/1]).
|
||||
|
||||
% Internal function also exported for use in transactional bloc from pubsub plugins
|
||||
-export([add_subscription/3, delete_subscription/3,
|
||||
read_subscription/3, write_subscription/4]).
|
||||
read_subscription/3, write_subscription/4]).
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
||||
|
||||
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
|
||||
|
||||
-define(PUBSUB_DIGEST_FREQUENCY,
|
||||
<<"pubsub#digest_frequency">>).
|
||||
|
||||
-define(PUBSUB_DIGEST_FREQUENCY, <<"pubsub#digest_frequency">>).
|
||||
-define(PUBSUB_EXPIRE, <<"pubsub#expire">>).
|
||||
|
||||
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
||||
|
||||
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
||||
|
||||
-define(PUBSUB_SUBSCRIPTION_TYPE,
|
||||
<<"pubsub#subscription_type">>).
|
||||
|
||||
-define(PUBSUB_SUBSCRIPTION_DEPTH,
|
||||
<<"pubsub#subscription_depth">>).
|
||||
|
||||
-define(DELIVER_LABEL,
|
||||
<<"Whether an entity wants to receive or "
|
||||
"disable notifications">>).
|
||||
|
||||
-define(DIGEST_LABEL,
|
||||
<<"Whether an entity wants to receive digests "
|
||||
"(aggregations) of notifications or all "
|
||||
"notifications individually">>).
|
||||
|
||||
-define(DIGEST_FREQUENCY_LABEL,
|
||||
<<"The minimum number of milliseconds between "
|
||||
"sending any two notification digests">>).
|
||||
|
||||
-define(EXPIRE_LABEL,
|
||||
<<"The DateTime at which a leased subscription "
|
||||
"will end or has ended">>).
|
||||
|
||||
-define(INCLUDE_BODY_LABEL,
|
||||
<<"Whether an entity wants to receive an "
|
||||
"XMPP message body in addition to the "
|
||||
"payload format">>).
|
||||
|
||||
-define(SHOW_VALUES_LABEL,
|
||||
<<"The presence states for which an entity "
|
||||
"wants to receive notifications">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_LABEL,
|
||||
<<"Type of notification to receive">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_LABEL,
|
||||
<<"Depth from subscription for which to "
|
||||
"receive notifications">>).
|
||||
|
||||
-define(SHOW_VALUE_AWAY_LABEL,
|
||||
<<"XMPP Show Value of Away">>).
|
||||
|
||||
-define(SHOW_VALUE_CHAT_LABEL,
|
||||
<<"XMPP Show Value of Chat">>).
|
||||
|
||||
-define(SHOW_VALUE_DND_LABEL,
|
||||
<<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||
|
||||
-define(SHOW_VALUE_ONLINE_LABEL,
|
||||
<<"Mere Availability in XMPP (No Show Value)">>).
|
||||
|
||||
-define(SHOW_VALUE_XA_LABEL,
|
||||
<<"XMPP Show Value of XA (Extended Away)">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL,
|
||||
<<"Receive notification of new items only">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL,
|
||||
<<"Receive notification of new nodes only">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL,
|
||||
<<"Receive notification from direct child "
|
||||
"nodes only">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL,
|
||||
<<"Receive notification from all descendent "
|
||||
"nodes">>).
|
||||
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
|
||||
-define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
|
||||
-define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
|
||||
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
|
||||
"(aggregations) of notifications or all notifications individually">>).
|
||||
-define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
|
||||
"sending any two notification digests">>).
|
||||
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
|
||||
-define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
|
||||
"XMPP message body in addition to the payload format">>).
|
||||
-define(SHOW_VALUES_LABEL, <<"The presence states for which an entity wants to receive notifications">>).
|
||||
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
|
||||
-define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
|
||||
-define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
|
||||
-define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
|
||||
-define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
|
||||
-define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, <<"Receive notification of new items only">>).
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, <<"Receive notification of new nodes only">>).
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
init() -> ok = create_table().
|
||||
|
||||
subscribe_node(JID, NodeID, Options) ->
|
||||
case catch mnesia:sync_dirty(fun add_subscription/3,
|
||||
[JID, NodeID, Options])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
subscribe_node(JID, NodeId, Options) ->
|
||||
case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
end.
|
||||
|
||||
unsubscribe_node(JID, NodeID, SubID) ->
|
||||
case catch mnesia:sync_dirty(fun delete_subscription/3,
|
||||
[JID, NodeID, SubID])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
unsubscribe_node(JID, NodeId, SubID) ->
|
||||
case catch mnesia:sync_dirty(fun delete_subscription/3, [JID, NodeId, SubID])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
end.
|
||||
|
||||
get_subscription(JID, NodeID, SubID) ->
|
||||
case catch mnesia:sync_dirty(fun read_subscription/3,
|
||||
[JID, NodeID, SubID])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
get_subscription(JID, NodeId, SubID) ->
|
||||
case catch mnesia:sync_dirty(fun read_subscription/3, [JID, NodeId, SubID])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
end.
|
||||
|
||||
set_subscription(JID, NodeID, SubID, Options) ->
|
||||
case catch mnesia:sync_dirty(fun write_subscription/4,
|
||||
[JID, NodeID, SubID, Options])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
set_subscription(JID, NodeId, SubID, Options) ->
|
||||
case catch mnesia:sync_dirty(fun write_subscription/4, [JID, NodeId, SubID, Options])
|
||||
of
|
||||
{'EXIT', {aborted, Error}} -> Error;
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
end.
|
||||
|
||||
|
||||
get_options_xform(Lang, Options) ->
|
||||
Keys = [deliver, show_values, subscription_type,
|
||||
subscription_depth],
|
||||
XFields = [get_option_xfield(Lang, Key, Options)
|
||||
|| Key <- Keys],
|
||||
Keys = [deliver, show_values, subscription_type, subscription_depth],
|
||||
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|
||||
{result,
|
||||
#xmlel{name = <<"x">>,
|
||||
#xmlel{name = <<"x">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
||||
children =
|
||||
[#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, <<"FORM_TYPE">>},
|
||||
{<<"type">>, <<"hidden">>}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||
++ XFields}}.
|
||||
[#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, <<"FORM_TYPE">>},
|
||||
{<<"type">>, <<"hidden">>}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||
++ XFields}}.
|
||||
|
||||
parse_options_xform(XFields) ->
|
||||
case xml:remove_cdata(XFields) of
|
||||
[#xmlel{name = <<"x">>} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
Opts = set_xoption(XData, []),
|
||||
{result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
_ -> {result, []}
|
||||
[#xmlel{name = <<"x">>} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
Opts = set_xoption(XData, []),
|
||||
{result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
_ -> {result, []}
|
||||
end.
|
||||
|
||||
%%====================================================================
|
||||
@ -196,69 +138,67 @@ parse_options_xform(XFields) ->
|
||||
%%====================================================================
|
||||
create_table() ->
|
||||
case mnesia:create_table(pubsub_subscription,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes,
|
||||
record_info(fields, pubsub_subscription)},
|
||||
{type, set}])
|
||||
of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, {already_exists, _}} -> ok;
|
||||
Other -> Other
|
||||
[{disc_copies, [node()]},
|
||||
{attributes,
|
||||
record_info(fields, pubsub_subscription)},
|
||||
{type, set}])
|
||||
of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, {already_exists, _}} -> ok;
|
||||
Other -> Other
|
||||
end.
|
||||
|
||||
-spec(add_subscription/3 ::
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeID :: mod_pubsub:nodeIdx(),
|
||||
Options :: [] | mod_pubsub:subOptions())
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeId :: mod_pubsub:nodeIdx(),
|
||||
Options :: [] | mod_pubsub:subOptions())
|
||||
-> SubId :: mod_pubsub:subId()
|
||||
).
|
||||
).
|
||||
|
||||
add_subscription(_JID, _NodeID, []) -> make_subid();
|
||||
add_subscription(_JID, _NodeID, Options) ->
|
||||
add_subscription(_JID, _NodeId, []) -> make_subid();
|
||||
add_subscription(_JID, _NodeId, Options) ->
|
||||
SubID = make_subid(),
|
||||
mnesia:write(#pubsub_subscription{subid = SubID,
|
||||
options = Options}),
|
||||
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}),
|
||||
SubID.
|
||||
|
||||
-spec(delete_subscription/3 ::
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeID :: _,
|
||||
SubId :: mod_pubsub:subId())
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeId :: _,
|
||||
SubId :: mod_pubsub:subId())
|
||||
-> ok
|
||||
).
|
||||
).
|
||||
|
||||
delete_subscription(_JID, _NodeID, SubID) ->
|
||||
delete_subscription(_JID, _NodeId, SubID) ->
|
||||
mnesia:delete({pubsub_subscription, SubID}).
|
||||
|
||||
-spec(read_subscription/3 ::
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeID :: _,
|
||||
SubID :: mod_pubsub:subId())
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeId :: _,
|
||||
SubID :: mod_pubsub:subId())
|
||||
-> mod_pubsub:pubsubSubscription()
|
||||
| {error, notfound}
|
||||
).
|
||||
| {error, notfound}
|
||||
).
|
||||
|
||||
read_subscription(_JID, _NodeID, SubID) ->
|
||||
read_subscription(_JID, _NodeId, SubID) ->
|
||||
case mnesia:read({pubsub_subscription, SubID}) of
|
||||
[Sub] -> Sub;
|
||||
_ -> {error, notfound}
|
||||
[Sub] -> Sub;
|
||||
_ -> {error, notfound}
|
||||
end.
|
||||
|
||||
-spec(write_subscription/4 ::
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeID :: _,
|
||||
SubID :: mod_pubsub:subId(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
(
|
||||
_JID :: ljid(),
|
||||
_NodeId :: _,
|
||||
SubID :: mod_pubsub:subId(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
-> ok
|
||||
).
|
||||
).
|
||||
|
||||
write_subscription(_JID, _NodeID, SubID, Options) ->
|
||||
mnesia:write(#pubsub_subscription{subid = SubID,
|
||||
options = Options}).
|
||||
write_subscription(_JID, _NodeId, SubID, Options) ->
|
||||
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}).
|
||||
|
||||
-spec(make_subid/0 :: () -> SubId::mod_pubsub:subId()).
|
||||
make_subid() ->
|
||||
@ -274,43 +214,42 @@ make_subid() ->
|
||||
set_xoption([], Opts) -> Opts;
|
||||
set_xoption([{Var, Value} | T], Opts) ->
|
||||
NewOpts = case var_xfield(Var) of
|
||||
{error, _} -> Opts;
|
||||
Key ->
|
||||
Val = val_xfield(Key, Value),
|
||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||
end,
|
||||
{error, _} -> Opts;
|
||||
Key ->
|
||||
Val = val_xfield(Key, Value),
|
||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||
end,
|
||||
set_xoption(T, NewOpts).
|
||||
|
||||
%% Return the options list's key for an XForm var.
|
||||
%% Convert Values for option list's Key.
|
||||
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
||||
var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) ->
|
||||
digest_frequency;
|
||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
|
||||
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) ->
|
||||
subscription_type;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
|
||||
subscription_depth;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
|
||||
var_xfield(_) -> {error, badarg}.
|
||||
|
||||
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
||||
%val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||
%val_xfield(digest_frequency, [Val]) ->
|
||||
% jlib:binary_to_integer(Val);
|
||||
%val_xfield(expire, [Val]) ->
|
||||
% jlib:datetime_string_to_timestamp(Val);
|
||||
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest_frequency, [Val]) ->
|
||||
case catch jlib:binary_to_integer(Val) of
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
|
||||
val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(show_values, Vals) -> Vals;
|
||||
val_xfield(subscription_type, [<<"items">>]) -> items;
|
||||
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
||||
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
||||
val_xfield(subscription_depth, [Depth]) ->
|
||||
case catch jlib:binary_to_integer(Depth) of
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
end.
|
||||
|
||||
%% Convert XForm booleans to Erlang booleans.
|
||||
@ -321,31 +260,30 @@ xopt_to_bool(<<"true">>) -> true;
|
||||
xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
|
||||
|
||||
-spec(get_option_xfield/3 ::
|
||||
(
|
||||
Lang :: binary(),
|
||||
Key :: atom(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
(
|
||||
Lang :: binary(),
|
||||
Key :: atom(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
-> xmlel()
|
||||
).
|
||||
).
|
||||
|
||||
%% Return a field for an XForm for Key, with data filled in, if
|
||||
%% applicable, from Options.
|
||||
get_option_xfield(Lang, Key, Options) ->
|
||||
Var = xfield_var(Key),
|
||||
Label = xfield_label(Key),
|
||||
{Type, OptEls} = type_and_options(xfield_type(Key),
|
||||
Lang),
|
||||
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
|
||||
Vals = case lists:keysearch(Key, 1, Options) of
|
||||
{value, {_, Val}} ->
|
||||
[tr_xfield_values(Vals)
|
||||
|| Vals <- xfield_val(Key, Val)];
|
||||
false -> []
|
||||
end,
|
||||
{value, {_, Val}} ->
|
||||
[tr_xfield_values(Vals)
|
||||
|| Vals <- xfield_val(Key, Val)];
|
||||
false -> []
|
||||
end,
|
||||
#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||
{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children = OptEls ++ Vals}.
|
||||
attrs =
|
||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||
{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children = OptEls ++ Vals}.
|
||||
|
||||
type_and_options({Type, Options}, Lang) ->
|
||||
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
||||
@ -353,42 +291,26 @@ type_and_options(Type, _Lang) -> {Type, []}.
|
||||
|
||||
tr_xfield_options({Value, Label}, Lang) ->
|
||||
#xmlel{name = <<"option">>,
|
||||
attrs =
|
||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}]}.
|
||||
attrs =
|
||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}]}.
|
||||
|
||||
tr_xfield_values(Value) ->
|
||||
%% Return the XForm variable name for a subscription option key.
|
||||
%% Return the XForm variable type for a subscription option key.
|
||||
%% Return the XForm variable name for a subscription option key.
|
||||
%% Return the XForm variable type for a subscription option key.
|
||||
#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}.
|
||||
|
||||
-spec(xfield_var/1 ::
|
||||
(
|
||||
Var :: 'deliver'
|
||||
% | 'digest'
|
||||
% | 'digest_frequency'
|
||||
% | 'expire'
|
||||
% | 'include_body'
|
||||
| 'show_values'
|
||||
| 'subscription_type'
|
||||
| 'subscription_depth')
|
||||
-> binary()
|
||||
).
|
||||
children = [{xmlcdata, Value}]}.
|
||||
|
||||
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
||||
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
||||
%xfield_var(digest_frequency) ->
|
||||
% ?PUBSUB_DIGEST_FREQUENCY;
|
||||
%xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
||||
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
||||
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
||||
xfield_var(subscription_type) ->
|
||||
?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var(subscription_depth) ->
|
||||
?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
|
||||
xfield_type(deliver) -> <<"boolean">>;
|
||||
%xfield_type(digest) -> <<"boolean">>;
|
||||
@ -397,52 +319,31 @@ xfield_type(deliver) -> <<"boolean">>;
|
||||
%xfield_type(include_body) -> <<"boolean">>;
|
||||
xfield_type(show_values) ->
|
||||
{<<"list-multi">>,
|
||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||
xfield_type(subscription_type) ->
|
||||
{<<"list-single">>,
|
||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||
xfield_type(subscription_depth) ->
|
||||
{<<"list-single">>,
|
||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||
|
||||
%% Return the XForm variable label for a subscription option key.
|
||||
xfield_label(deliver) -> ?DELIVER_LABEL;
|
||||
%xfield_label(digest) -> ?DIGEST_LABEL;
|
||||
%xfield_label(digest_frequency) ->
|
||||
% ?DIGEST_FREQUENCY_LABEL;
|
||||
%xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
|
||||
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
||||
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
||||
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
||||
%% Return the XForm value for a subscription option key.
|
||||
%% Convert erlang booleans to XForms.
|
||||
xfield_label(subscription_type) ->
|
||||
?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label(subscription_depth) ->
|
||||
?SUBSCRIPTION_DEPTH_LABEL.
|
||||
|
||||
-spec(xfield_val/2 ::
|
||||
(
|
||||
Field :: 'deliver'
|
||||
% | 'digest'
|
||||
% | 'digest_frequency'
|
||||
% | 'expire'
|
||||
% | 'include_body'
|
||||
| 'show_values'
|
||||
| 'subscription_type'
|
||||
| 'subscription_depth',
|
||||
Val :: boolean()
|
||||
| binary()
|
||||
| integer()
|
||||
| [binary()])
|
||||
% | erlang:timestamp())
|
||||
-> [binary()]
|
||||
).
|
||||
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
|
||||
|
||||
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||
%xfield_val(digest, Val) -> [bool_to_xopt(Val)];
|
||||
@ -450,7 +351,7 @@ xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||
% [iolist_to_binary(integer_to_list(Val))];
|
||||
%xfield_val(expire, Val) ->
|
||||
% [jlib:now_to_utc_string(Val)];
|
||||
%%xfield_val(include_body, Val) -> [bool_to_xopt(Val)];
|
||||
%xfield_val(include_body, Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val(show_values, Val) -> Val;
|
||||
xfield_val(subscription_type, items) -> [<<"items">>];
|
||||
xfield_val(subscription_type, nodes) -> [<<"nodes">>];
|
||||
|
@ -22,98 +22,45 @@
|
||||
%%% ====================================================================
|
||||
|
||||
-module(pubsub_subscription_odbc).
|
||||
|
||||
-author("pablo.polvorin@process-one.net").
|
||||
|
||||
%% API
|
||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
||||
get_subscription/3, set_subscription/4,
|
||||
get_options_xform/2, parse_options_xform/1]).
|
||||
get_subscription/3, set_subscription/4,
|
||||
get_options_xform/2, parse_options_xform/1]).
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
||||
|
||||
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
|
||||
|
||||
-define(PUBSUB_DIGEST_FREQUENCY,
|
||||
<<"pubsub#digest_frequency">>).
|
||||
|
||||
-define(PUBSUB_DIGEST_FREQUENCY, <<"pubsub#digest_frequency">>).
|
||||
-define(PUBSUB_EXPIRE, <<"pubsub#expire">>).
|
||||
|
||||
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
||||
|
||||
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
||||
|
||||
-define(PUBSUB_SUBSCRIPTION_TYPE,
|
||||
<<"pubsub#subscription_type">>).
|
||||
|
||||
-define(PUBSUB_SUBSCRIPTION_DEPTH,
|
||||
<<"pubsub#subscription_depth">>).
|
||||
|
||||
-define(DELIVER_LABEL,
|
||||
<<"Whether an entity wants to receive or "
|
||||
"disable notifications">>).
|
||||
|
||||
-define(DIGEST_LABEL,
|
||||
<<"Whether an entity wants to receive digests "
|
||||
"(aggregations) of notifications or all "
|
||||
"notifications individually">>).
|
||||
|
||||
-define(DIGEST_FREQUENCY_LABEL,
|
||||
<<"The minimum number of milliseconds between "
|
||||
"sending any two notification digests">>).
|
||||
|
||||
-define(EXPIRE_LABEL,
|
||||
<<"The DateTime at which a leased subscription "
|
||||
"will end or has ended">>).
|
||||
|
||||
-define(INCLUDE_BODY_LABEL,
|
||||
<<"Whether an entity wants to receive an "
|
||||
"XMPP message body in addition to the "
|
||||
"payload format">>).
|
||||
|
||||
-define(SHOW_VALUES_LABEL,
|
||||
<<"The presence states for which an entity "
|
||||
"wants to receive notifications">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_LABEL,
|
||||
<<"Type of notification to receive">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_LABEL,
|
||||
<<"Depth from subscription for which to "
|
||||
"receive notifications">>).
|
||||
|
||||
-define(SHOW_VALUE_AWAY_LABEL,
|
||||
<<"XMPP Show Value of Away">>).
|
||||
|
||||
-define(SHOW_VALUE_CHAT_LABEL,
|
||||
<<"XMPP Show Value of Chat">>).
|
||||
|
||||
-define(SHOW_VALUE_DND_LABEL,
|
||||
<<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||
|
||||
-define(SHOW_VALUE_ONLINE_LABEL,
|
||||
<<"Mere Availability in XMPP (No Show Value)">>).
|
||||
|
||||
-define(SHOW_VALUE_XA_LABEL,
|
||||
<<"XMPP Show Value of XA (Extended Away)">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL,
|
||||
<<"Receive notification of new items only">>).
|
||||
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL,
|
||||
<<"Receive notification of new nodes only">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL,
|
||||
<<"Receive notification from direct child "
|
||||
"nodes only">>).
|
||||
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL,
|
||||
<<"Receive notification from all descendent "
|
||||
"nodes">>).
|
||||
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
|
||||
-define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
|
||||
-define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
|
||||
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
|
||||
"(aggregations) of notifications or all notifications individually">>).
|
||||
-define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
|
||||
"sending any two notification digests">>).
|
||||
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
|
||||
-define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
|
||||
"XMPP message body in addition to the payload format">>).
|
||||
-define(SHOW_VALUES_LABEL, <<"The presence states for which an entity wants to receive notifications">>).
|
||||
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
|
||||
-define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
|
||||
-define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
|
||||
-define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
|
||||
-define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
|
||||
-define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, <<"Receive notification of new items only">>).
|
||||
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, <<"Receive notification of new nodes only">>).
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
|
||||
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
|
||||
|
||||
-define(DB_MOD, pubsub_db_odbc).
|
||||
%%====================================================================
|
||||
@ -123,99 +70,92 @@
|
||||
init() -> ok = create_table().
|
||||
|
||||
-spec(subscribe_node/3 ::
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeID :: _,
|
||||
Options :: mod_pubsub:subOptions())
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeId :: _,
|
||||
Options :: [] | mod_pubsub:subOptions())
|
||||
-> {result, mod_pubsub:subId()}
|
||||
).
|
||||
subscribe_node(_JID, _NodeID, Options) ->
|
||||
).
|
||||
subscribe_node(_JID, _NodeId, Options) ->
|
||||
SubID = make_subid(),
|
||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid =
|
||||
SubID,
|
||||
options = Options}),
|
||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID, options = Options}),
|
||||
{result, SubID}.
|
||||
|
||||
-spec(unsubscribe_node/3 ::
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeID :: _,
|
||||
SubID :: mod_pubsub:subId())
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeId :: _,
|
||||
SubID :: mod_pubsub:subId())
|
||||
-> {result, mod_pubsub:subscription()}
|
||||
| {error, notfound}
|
||||
).
|
||||
unsubscribe_node(_JID, _NodeID, SubID) ->
|
||||
| {error, notfound}
|
||||
).
|
||||
unsubscribe_node(_JID, _NodeId, SubID) ->
|
||||
case (?DB_MOD):read_subscription(SubID) of
|
||||
{ok, Sub} ->
|
||||
(?DB_MOD):delete_subscription(SubID), {result, Sub};
|
||||
notfound -> {error, notfound}
|
||||
{ok, Sub} -> (?DB_MOD):delete_subscription(SubID), {result, Sub};
|
||||
notfound -> {error, notfound}
|
||||
end.
|
||||
|
||||
-spec(get_subscription/3 ::
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeID :: _,
|
||||
SubId :: mod_pubsub:subId())
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeId :: _,
|
||||
SubId :: mod_pubsub:subId())
|
||||
-> {result, mod_pubsub:subscription()}
|
||||
| {error, notfound}
|
||||
).
|
||||
get_subscription(_JID, _NodeID, SubID) ->
|
||||
| {error, notfound}
|
||||
).
|
||||
get_subscription(_JID, _NodeId, SubID) ->
|
||||
case (?DB_MOD):read_subscription(SubID) of
|
||||
{ok, Sub} -> {result, Sub};
|
||||
notfound -> {error, notfound}
|
||||
{ok, Sub} -> {result, Sub};
|
||||
notfound -> {error, notfound}
|
||||
end.
|
||||
|
||||
-spec(set_subscription/4 ::
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeID :: _,
|
||||
SubId :: mod_pubsub:subId(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
(
|
||||
_JID :: _,
|
||||
_NodeId :: _,
|
||||
SubId :: mod_pubsub:subId(),
|
||||
Options :: mod_pubsub:subOptions())
|
||||
-> {result, ok}
|
||||
).
|
||||
set_subscription(_JID, _NodeID, SubID, Options) ->
|
||||
).
|
||||
set_subscription(_JID, _NodeId, SubID, Options) ->
|
||||
case (?DB_MOD):read_subscription(SubID) of
|
||||
{ok, _} ->
|
||||
(?DB_MOD):update_subscription(#pubsub_subscription{subid
|
||||
= SubID,
|
||||
options =
|
||||
Options}),
|
||||
{result, ok};
|
||||
notfound ->
|
||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid =
|
||||
SubID,
|
||||
options = Options}),
|
||||
{result, ok}
|
||||
{ok, _} ->
|
||||
(?DB_MOD):update_subscription(#pubsub_subscription{subid = SubID,
|
||||
options = Options}),
|
||||
{result, ok};
|
||||
notfound ->
|
||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID,
|
||||
options = Options}),
|
||||
{result, ok}
|
||||
end.
|
||||
|
||||
get_options_xform(Lang, Options) ->
|
||||
Keys = [deliver, show_values, subscription_type, subscription_depth],
|
||||
XFields = [get_option_xfield(Lang, Key, Options)
|
||||
|| Key <- Keys],
|
||||
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|
||||
{result,
|
||||
#xmlel{name = <<"x">>,
|
||||
#xmlel{name = <<"x">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
||||
children =
|
||||
[#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, <<"FORM_TYPE">>},
|
||||
{<<"type">>, <<"hidden">>}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||
++ XFields}}.
|
||||
[#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, <<"FORM_TYPE">>},
|
||||
{<<"type">>, <<"hidden">>}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||
++ XFields}}.
|
||||
|
||||
parse_options_xform(XFields) ->
|
||||
case xml:remove_cdata(XFields) of
|
||||
[#xmlel{name = <<"x">>} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
Opts = set_xoption(XData, []),
|
||||
{result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
_ -> {result, []}
|
||||
[#xmlel{name = <<"x">>} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
Opts = set_xoption(XData, []),
|
||||
{result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
_ -> {result, []}
|
||||
end.
|
||||
|
||||
%%====================================================================
|
||||
@ -237,43 +177,42 @@ make_subid() ->
|
||||
set_xoption([], Opts) -> Opts;
|
||||
set_xoption([{Var, Value} | T], Opts) ->
|
||||
NewOpts = case var_xfield(Var) of
|
||||
{error, _} -> Opts;
|
||||
Key ->
|
||||
Val = val_xfield(Key, Value),
|
||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||
end,
|
||||
{error, _} -> Opts;
|
||||
Key ->
|
||||
Val = val_xfield(Key, Value),
|
||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||
end,
|
||||
set_xoption(T, NewOpts).
|
||||
|
||||
%% Return the options list's key for an XForm var.
|
||||
%% Convert Values for option list's Key.
|
||||
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
||||
%var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||
%var_xfield(?PUBSUB_DIGEST_FREQUENCY) ->
|
||||
% digest_frequency;
|
||||
%var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||
%var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||
var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
|
||||
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) ->
|
||||
subscription_type;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
|
||||
subscription_depth;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
|
||||
var_xfield(_) -> {error, badarg}.
|
||||
|
||||
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
||||
%val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||
%val_xfield(digest_frequency, [Val]) ->
|
||||
% jlib:binary_to_integer(Val);
|
||||
%val_xfield(expire, [Val]) ->
|
||||
% jlib:datetime_string_to_timestamp(Val);
|
||||
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest_frequency, [Val]) ->
|
||||
case catch jlib:binary_to_integer(Val) of
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
|
||||
val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(show_values, Vals) -> Vals;
|
||||
val_xfield(subscription_type, [<<"items">>]) -> items;
|
||||
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
||||
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
||||
val_xfield(subscription_depth, [Depth]) ->
|
||||
case catch jlib:binary_to_integer(Depth) of
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||
end.
|
||||
|
||||
%% Convert XForm booleans to Erlang booleans.
|
||||
@ -288,19 +227,18 @@ xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
|
||||
get_option_xfield(Lang, Key, Options) ->
|
||||
Var = xfield_var(Key),
|
||||
Label = xfield_label(Key),
|
||||
{Type, OptEls} = type_and_options(xfield_type(Key),
|
||||
Lang),
|
||||
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
|
||||
Vals = case lists:keysearch(Key, 1, Options) of
|
||||
{value, {_, Val}} ->
|
||||
[tr_xfield_values(Vals)
|
||||
|| Vals <- xfield_val(Key, Val)];
|
||||
false -> []
|
||||
end,
|
||||
{value, {_, Val}} ->
|
||||
[tr_xfield_values(Vals)
|
||||
|| Vals <- xfield_val(Key, Val)];
|
||||
false -> []
|
||||
end,
|
||||
#xmlel{name = <<"field">>,
|
||||
attrs =
|
||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||
{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children = OptEls ++ Vals}.
|
||||
attrs =
|
||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||
{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children = OptEls ++ Vals}.
|
||||
|
||||
type_and_options({Type, Options}, Lang) ->
|
||||
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
||||
@ -308,29 +246,26 @@ type_and_options(Type, _Lang) -> {Type, []}.
|
||||
|
||||
tr_xfield_options({Value, Label}, Lang) ->
|
||||
#xmlel{name = <<"option">>,
|
||||
attrs =
|
||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}]}.
|
||||
attrs =
|
||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||
children =
|
||||
[#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}]}.
|
||||
|
||||
tr_xfield_values(Value) ->
|
||||
%% Return the XForm variable name for a subscription option key.
|
||||
%% Return the XForm variable type for a subscription option key.
|
||||
%% Return the XForm variable name for a subscription option key.
|
||||
%% Return the XForm variable type for a subscription option key.
|
||||
#xmlel{name = <<"value">>, attrs = [],
|
||||
children = [{xmlcdata, Value}]}.
|
||||
children = [{xmlcdata, Value}]}.
|
||||
|
||||
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
||||
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
||||
%xfield_var(digest_frequency) ->
|
||||
% ?PUBSUB_DIGEST_FREQUENCY;
|
||||
%xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
||||
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
||||
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
||||
xfield_var(subscription_type) ->
|
||||
?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var(subscription_depth) ->
|
||||
?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
|
||||
xfield_type(deliver) -> <<"boolean">>;
|
||||
%xfield_type(digest) -> <<"boolean">>;
|
||||
@ -339,34 +274,31 @@ xfield_type(deliver) -> <<"boolean">>;
|
||||
%xfield_type(include_body) -> <<"boolean">>;
|
||||
xfield_type(show_values) ->
|
||||
{<<"list-multi">>,
|
||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||
xfield_type(subscription_type) ->
|
||||
{<<"list-single">>,
|
||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||
xfield_type(subscription_depth) ->
|
||||
{<<"list-single">>,
|
||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||
|
||||
%% Return the XForm variable label for a subscription option key.
|
||||
xfield_label(deliver) -> ?DELIVER_LABEL;
|
||||
%xfield_label(digest) -> ?DIGEST_LABEL;
|
||||
%xfield_label(digest_frequency) ->
|
||||
% ?DIGEST_FREQUENCY_LABEL;
|
||||
%xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
|
||||
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
||||
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
||||
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
||||
%% Return the XForm value for a subscription option key.
|
||||
%% Convert erlang booleans to XForms.
|
||||
xfield_label(subscription_type) ->
|
||||
?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label(subscription_depth) ->
|
||||
?SUBSCRIPTION_DEPTH_LABEL.
|
||||
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
|
||||
|
||||
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||
%xfield_val(digest, Val) -> [bool_to_xopt(Val)];
|
||||
|
@ -813,7 +813,7 @@ pubsub(Config) ->
|
||||
node = Node,
|
||||
jid = my_jid(Config)}}]}),
|
||||
?recv2(
|
||||
#message{sub_els = [#pubsub_event{}, #delay{}, #legacy_delay{}]},
|
||||
#message{sub_els = [#pubsub_event{}, #delay{}]},
|
||||
#iq{type = result, id = I1}),
|
||||
%% Get subscriptions
|
||||
true = lists:member(?PUBSUB("retrieve-subscriptions"), Features),
|
||||
@ -860,8 +860,7 @@ pubsub(Config) ->
|
||||
#message{sub_els = [#pubsub_event{
|
||||
items = [#pubsub_event_items{
|
||||
node = Node,
|
||||
retract = [ItemID]}]},
|
||||
#shim{headers = [{<<"Collection">>, Node}]}]}),
|
||||
retract = [ItemID]}]}]}),
|
||||
%% Unsubscribe from node "presence"
|
||||
#iq{type = result, sub_els = []} =
|
||||
send_recv(Config,
|
||||
|
@ -94,7 +94,8 @@
|
||||
{mod_offline, [{db_type, odbc}]},
|
||||
{mod_privacy, [{db_type, odbc}]},
|
||||
{mod_private, [{db_type, odbc}]},
|
||||
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode},
|
||||
{mod_pubsub, [{db_type, odbc},
|
||||
{access_createnode, pubsub_createnode},
|
||||
{ignore_pep_from_offline, true},
|
||||
{last_item_cache, false},
|
||||
{plugins, ["flat", "hometree", "pep"]}]},
|
||||
@ -114,7 +115,8 @@
|
||||
{mod_offline, [{db_type, odbc}]},
|
||||
{mod_privacy, [{db_type, odbc}]},
|
||||
{mod_private, [{db_type, odbc}]},
|
||||
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode},
|
||||
{mod_pubsub, [{db_type, odbc},
|
||||
{access_createnode, pubsub_createnode},
|
||||
{ignore_pep_from_offline, true},
|
||||
{last_item_cache, false},
|
||||
{plugins, ["flat", "hometree", "pep"]}]},
|
||||
@ -133,7 +135,8 @@
|
||||
{mod_offline, [{db_type, odbc}]},
|
||||
{mod_privacy, [{db_type, odbc}]},
|
||||
{mod_private, [{db_type, odbc}]},
|
||||
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode},
|
||||
{mod_pubsub, [{db_type, odbc},
|
||||
{access_createnode, pubsub_createnode},
|
||||
{ignore_pep_from_offline, true},
|
||||
{last_item_cache, false},
|
||||
{plugins, ["flat", "hometree", "pep"]}]},
|
||||
|
@ -26,7 +26,8 @@ host_config:
|
||||
db_type: odbc
|
||||
mod_private:
|
||||
db_type: odbc
|
||||
mod_pubsub_odbc:
|
||||
mod_pubsub:
|
||||
db_type: odbc
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
@ -76,7 +77,8 @@ Welcome to this XMPP server."
|
||||
db_type: odbc
|
||||
mod_private:
|
||||
db_type: odbc
|
||||
mod_pubsub_odbc:
|
||||
mod_pubsub:
|
||||
db_type: odbc
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
@ -132,7 +134,8 @@ Welcome to this XMPP server."
|
||||
db_type: odbc
|
||||
mod_private:
|
||||
db_type: odbc
|
||||
mod_pubsub_odbc:
|
||||
mod_pubsub:
|
||||
db_type: odbc
|
||||
access_createnode: pubsub_createnode
|
||||
ignore_pep_from_offline: true
|
||||
last_item_cache: false
|
||||
|
Loading…
Reference in New Issue
Block a user