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
|
%% Pubsub constants
|
||||||
-define(ERR_EXTENDED(E, C),
|
-define(ERR_EXTENDED(E, C), mod_pubsub:extended_error(E, C)).
|
||||||
mod_pubsub:extended_error(E, C)).
|
|
||||||
|
|
||||||
%% The actual limit can be configured with mod_pubsub's option max_items_node
|
%% The actual limit can be configured with mod_pubsub's option max_items_node
|
||||||
-define(MAXITEMS, 10).
|
-define(MAXITEMS, 10).
|
||||||
@ -40,7 +39,6 @@
|
|||||||
%% -------------------------------
|
%% -------------------------------
|
||||||
%% Pubsub types
|
%% Pubsub types
|
||||||
|
|
||||||
%% @type hostPubsub() = string().
|
|
||||||
-type(hostPubsub() :: binary()).
|
-type(hostPubsub() :: binary()).
|
||||||
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
||||||
%% <tt>"pubsub.localhost"</tt>.</p>
|
%% <tt>"pubsub.localhost"</tt>.</p>
|
||||||
@ -59,12 +57,15 @@
|
|||||||
-type(nodeId() :: binary()).
|
-type(nodeId() :: binary()).
|
||||||
%% @type nodeId() = binary().
|
%% @type nodeId() = binary().
|
||||||
%% <p>A node is defined by a list of its ancestors. The last element is the name
|
%% <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:
|
%% of the current node. For example:
|
||||||
%% ```<<"/home/localhost/user">>'''</p>
|
%% ```<<"/home/localhost/user">>'''</p>
|
||||||
|
|
||||||
-type(nodeIdx() :: pos_integer()).
|
-type(nodeIdx() :: pos_integer() | binary()).
|
||||||
%% @type nodeIdx() = integer().
|
%% @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() :: binary()).
|
||||||
%% @type itemId() = string().
|
%% @type itemId() = string().
|
||||||
@ -72,28 +73,12 @@
|
|||||||
-type(subId() :: binary()).
|
-type(subId() :: binary()).
|
||||||
%% @type subId() = string().
|
%% @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() ::
|
-type(nodeOption() ::
|
||||||
{Option::atom(),
|
{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}
|
%% @type nodeOption() = {Option, Value}
|
||||||
%% Option = atom()
|
%% Option = atom()
|
||||||
@ -106,26 +91,9 @@
|
|||||||
Value::binary() | [binary()] | boolean()
|
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'
|
-type(affiliation() :: 'none'
|
||||||
| 'owner'
|
| 'owner'
|
||||||
@ -151,16 +119,11 @@
|
|||||||
).
|
).
|
||||||
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
%% @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'
|
-type(publishModel() :: 'publishers'
|
||||||
| 'subscribers'
|
| 'subscribers'
|
||||||
| 'open'
|
| 'open'
|
||||||
).
|
).
|
||||||
|
%% @type publishModel() = 'publishers' | 'subscribers' | 'open'
|
||||||
|
|
||||||
-record(pubsub_index,
|
-record(pubsub_index,
|
||||||
{
|
{
|
||||||
@ -169,91 +132,42 @@
|
|||||||
free :: [mod_pubsub:nodeIdx()]
|
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,
|
-record(pubsub_node,
|
||||||
{
|
{
|
||||||
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
|
nodeid ,% :: {mod_pubsub:host(), mod_pubsub:nodeId()},
|
||||||
id ,%:: mod_pubsub:nodeIdx(),
|
id ,% :: mod_pubsub:nodeIdx(),
|
||||||
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()],
|
parents = [] ,% :: [mod_pubsub:nodeId(),...],
|
||||||
type = <<"flat">> ,%:: binary(),
|
type = <<"flat">>,% :: binary(),
|
||||||
owners = [] ,%:: [Owner::ljid(),...],
|
owners = [] ,% :: [jlib:ljid(),...],
|
||||||
options = [] %:: mod_pubsub:nodeOptions()
|
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,
|
-record(pubsub_state,
|
||||||
{
|
{
|
||||||
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()},
|
stateid ,% :: {jlib:ljid(), mod_pubsub:nodeIdx()},
|
||||||
items = [] ,%:: [ItemId::mod_pubsub:itemId()],
|
items = [] ,% :: [mod_pubsub:itemId(),...],
|
||||||
affiliation = 'none' ,%:: mod_pubsub:affiliation(),
|
affiliation = 'none',% :: mod_pubsub:affiliation(),
|
||||||
subscriptions = [] %:: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
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,
|
-record(pubsub_item,
|
||||||
{
|
{
|
||||||
itemid ,%:: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
itemid ,% :: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
||||||
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
creation = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
|
||||||
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
modification = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
|
||||||
payload = [] %:: mod_pubsub:payload()
|
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,
|
-record(pubsub_subscription,
|
||||||
{
|
{
|
||||||
subid ,%:: mod_pubsub:subId(),
|
subid ,% :: mod_pubsub:subId(),
|
||||||
options %:: [] | mod_pubsub:subOptions()
|
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,
|
-record(pubsub_last_item,
|
||||||
{
|
{
|
||||||
nodeid ,%:: mod_pubsub:nodeIdx(),
|
nodeid ,% :: mod_pubsub:nodeIdx(),
|
||||||
itemid ,%:: mod_pubsub:itemId(),
|
itemid ,% :: mod_pubsub:itemId(),
|
||||||
creation ,%:: {erlang:timestamp(), ljid()},
|
creation ,% :: {erlang:timestamp(), jlib:ljid()},
|
||||||
payload %:: mod_pubsub:payload()
|
payload % :: mod_pubsub:payload()
|
||||||
}).
|
}).
|
||||||
|
@ -32,191 +32,146 @@
|
|||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-type(host() :: mod_pubsub:host()
|
-type(host() :: mod_pubsub:host()).
|
||||||
| mod_pubsub_odbc:host()
|
-type(nodeId() :: mod_pubsub:nodeId()).
|
||||||
).
|
-type(nodeIdx() :: mod_pubsub:nodeIdx()).
|
||||||
|
-type(itemId() :: mod_pubsub:itemId()).
|
||||||
-type(nodeId() :: mod_pubsub:nodeId()
|
-type(pubsubNode() :: mod_pubsub:pubsubNode()).
|
||||||
| mod_pubsub_odbc:nodeId()
|
-type(pubsubState() :: mod_pubsub:pubsubState()).
|
||||||
).
|
-type(pubsubItem() :: mod_pubsub:pubsubItem()).
|
||||||
|
-type(subOptions() :: mod_pubsub:subOptions()).
|
||||||
-type(nodeIdx() :: mod_pubsub:nodeIdx()
|
-type(affiliation() :: mod_pubsub:affiliation()).
|
||||||
| mod_pubsub_odbc:nodeIdx()
|
-type(subscription() :: mod_pubsub:subscription()).
|
||||||
).
|
-type(subId() :: mod_pubsub:subId()).
|
||||||
|
-type(accessModel() :: mod_pubsub:accessModel()).
|
||||||
-type(itemId() :: mod_pubsub:itemId()
|
-type(publishModel() :: mod_pubsub:publishModel()).
|
||||||
| mod_pubsub_odbc:itemId()
|
-type(payload() :: mod_pubsub:payload()).
|
||||||
).
|
|
||||||
|
|
||||||
-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()
|
|
||||||
).
|
|
||||||
|
|
||||||
-callback init(Host :: binary(),
|
-callback init(Host :: binary(),
|
||||||
ServerHost :: binary(),
|
ServerHost :: binary(),
|
||||||
Opts :: [any()]) -> atom().
|
Opts :: [any()]) -> atom().
|
||||||
|
|
||||||
-callback terminate(Host :: host(),
|
-callback terminate(Host :: host(),
|
||||||
ServerHost :: binary()) -> atom().
|
ServerHost :: binary()) -> atom().
|
||||||
|
|
||||||
-callback options() -> [{atom(), any()}].
|
-callback options() -> [{atom(), any()}].
|
||||||
|
|
||||||
-callback features() -> [binary()].
|
-callback features() -> [binary()].
|
||||||
|
|
||||||
-callback create_node_permission(Host :: host(),
|
-callback create_node_permission(Host :: host(),
|
||||||
ServerHost :: binary(),
|
ServerHost :: binary(),
|
||||||
Node :: nodeId(),
|
Node :: nodeId(),
|
||||||
ParentNode :: nodeId(),
|
ParentNode :: nodeId(),
|
||||||
Owner :: jid(), Access :: atom()) ->
|
Owner :: jid(), Access :: atom()) ->
|
||||||
{result, boolean()}.
|
{result, boolean()}.
|
||||||
|
|
||||||
-callback create_node(NodeIdx :: nodeIdx(),
|
-callback create_node(NodeIdx :: nodeIdx(),
|
||||||
Owner :: jid()) ->
|
Owner :: jid()) ->
|
||||||
{result, {default, broadcast}}.
|
{result, {default, broadcast}}.
|
||||||
|
|
||||||
-callback delete_node(Nodes :: [pubsubNode(),...]) ->
|
-callback delete_node(Nodes :: [pubsubNode(),...]) ->
|
||||||
{result,
|
{result,
|
||||||
{default, broadcast,
|
{default, broadcast,
|
||||||
[{pubsubNode(),
|
[{pubsubNode(),
|
||||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
|
||||||
{result,
|
{result,
|
||||||
{[],
|
{[],
|
||||||
[{pubsubNode(),
|
[{pubsubNode(),
|
||||||
[{ljid(), [{subscription(), subId()}]},...]},...]
|
[{ljid(), [{subscription(), subId()}]},...]},...]
|
||||||
}
|
}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-callback purge_node(NodeIdx :: nodeIdx(),
|
-callback purge_node(NodeIdx :: nodeIdx(),
|
||||||
Owner :: jid()) ->
|
Owner :: jid()) ->
|
||||||
{result, {default, broadcast}} |
|
{result, {default, broadcast}} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback subscribe_node(NodeIdx :: nodeIdx(),
|
-callback subscribe_node(NodeIdx :: nodeIdx(),
|
||||||
Sender :: jid(),
|
Sender :: jid(),
|
||||||
Subscriber :: ljid(),
|
Subscriber :: jid(),
|
||||||
AccessModel :: accessModel(),
|
AccessModel :: accessModel(),
|
||||||
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
|
||||||
PresenceSubscription :: boolean(),
|
PresenceSubscription :: boolean(),
|
||||||
RosterGroup :: boolean(),
|
RosterGroup :: boolean(),
|
||||||
Options :: subOptions()) ->
|
Options :: subOptions()) ->
|
||||||
{result, {default, subscribed, subId()}} |
|
{result, {default, subscribed, subId()}} |
|
||||||
{result, {default, subscribed, subId(), send_last}} |
|
{result, {default, subscribed, subId(), send_last}} |
|
||||||
{result, {default, pending, subId()}} |
|
{result, {default, pending, subId()}} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback unsubscribe_node(NodeIdx :: nodeIdx(),
|
-callback unsubscribe_node(NodeIdx :: nodeIdx(),
|
||||||
Sender :: jid(),
|
Sender :: jid(),
|
||||||
Subscriber :: ljid(),
|
Subscriber :: jid(),
|
||||||
SubId :: subId()) ->
|
SubId :: subId()) ->
|
||||||
{result, default} |
|
{result, default} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback publish_item(NodeId :: nodeIdx(),
|
-callback publish_item(NodeId :: nodeIdx(),
|
||||||
Publisher :: jid(),
|
Publisher :: jid(),
|
||||||
PublishModel :: publishModel(),
|
PublishModel :: publishModel(),
|
||||||
Max_Items :: non_neg_integer(),
|
Max_Items :: non_neg_integer(),
|
||||||
ItemId :: <<>> | itemId(),
|
ItemId :: <<>> | itemId(),
|
||||||
Payload :: payload()) ->
|
Payload :: payload()) ->
|
||||||
{result, {default, broadcast, [itemId()]}} |
|
{result, {default, broadcast, [itemId()]}} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback delete_item(NodeIdx :: nodeIdx(),
|
-callback delete_item(NodeIdx :: nodeIdx(),
|
||||||
Publisher :: jid(),
|
Publisher :: jid(),
|
||||||
PublishModel :: publishModel(),
|
PublishModel :: publishModel(),
|
||||||
ItemId :: <<>> | itemId()) ->
|
ItemId :: <<>> | itemId()) ->
|
||||||
{result, {default, broadcast}} |
|
{result, {default, broadcast}} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback remove_extra_items(NodeIdx :: nodeIdx(),
|
-callback remove_extra_items(NodeIdx :: nodeIdx(),
|
||||||
Max_Items :: unlimited | non_neg_integer(),
|
Max_Items :: unlimited | non_neg_integer(),
|
||||||
ItemIds :: [itemId()]) ->
|
ItemIds :: [itemId()]) ->
|
||||||
{result, {[itemId()], [itemId()]}
|
{result, {[itemId()], [itemId()]}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-callback get_node_affiliations(NodeIdx :: nodeIdx()) ->
|
-callback get_node_affiliations(NodeIdx :: nodeIdx()) ->
|
||||||
{result, [{ljid(), affiliation()}]}.
|
{result, [{ljid(), affiliation()}]}.
|
||||||
|
|
||||||
-callback get_entity_affiliations(Host :: host(),
|
-callback get_entity_affiliations(Host :: host(),
|
||||||
Owner :: jid()) ->
|
Owner :: jid()) ->
|
||||||
{result, [{pubsubNode(), affiliation()}]}.
|
{result, [{pubsubNode(), affiliation()}]}.
|
||||||
|
|
||||||
-callback get_affiliation(NodeIdx :: nodeIdx(),
|
-callback get_affiliation(NodeIdx :: nodeIdx(),
|
||||||
Owner :: jid()) ->
|
Owner :: jid()) ->
|
||||||
{result, affiliation()}.
|
{result, affiliation()}.
|
||||||
|
|
||||||
-callback set_affiliation(NodeIdx :: nodeIdx(),
|
-callback set_affiliation(NodeIdx :: nodeIdx(),
|
||||||
Owner :: ljid(),
|
Owner :: jid(),
|
||||||
Affiliation :: affiliation()) ->
|
Affiliation :: affiliation()) ->
|
||||||
ok |
|
ok |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_node_subscriptions(NodeIdx :: nodeIdx()) ->
|
-callback get_node_subscriptions(NodeIdx :: nodeIdx()) ->
|
||||||
{result,
|
{result,
|
||||||
[{ljid(), subscription(), subId()}] |
|
[{ljid(), subscription(), subId()}] |
|
||||||
[{ljid(), none},...]
|
[{ljid(), none},...]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-callback get_entity_subscriptions(Host :: host(),
|
-callback get_entity_subscriptions(Host :: host(),
|
||||||
Owner :: jid()) ->
|
Key :: jid()) ->
|
||||||
{result, [{pubsubNode(), subscription(), subId(), ljid()}]
|
{result, [{pubsubNode(), subscription(), subId(), ljid()}]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-callback get_subscriptions(NodeIdx :: nodeIdx(),
|
-callback get_subscriptions(NodeIdx :: nodeIdx(),
|
||||||
Owner :: ljid()) ->
|
Owner :: jid()) ->
|
||||||
{result, [{subscription(), subId()}]}.
|
{result, [{subscription(), subId()}]}.
|
||||||
|
|
||||||
-callback get_pending_nodes(Host :: host(),
|
-callback get_pending_nodes(Host :: host(),
|
||||||
Owner :: jid()) ->
|
Owner :: jid()) ->
|
||||||
{result, [nodeId()]}.
|
{result, [nodeId()]}.
|
||||||
|
|
||||||
-callback get_states(NodeIdx::nodeIdx()) ->
|
-callback get_states(NodeIdx::nodeIdx()) ->
|
||||||
{result, [pubsubState()]}.
|
{result, [pubsubState()]}.
|
||||||
|
|
||||||
-callback get_state(NodeIdx :: nodeIdx(),
|
-callback get_state(NodeIdx :: nodeIdx(),
|
||||||
JID :: ljid()) ->
|
Key :: ljid()) ->
|
||||||
pubsubState().
|
pubsubState().
|
||||||
|
|
||||||
-callback set_state(State::pubsubState()) ->
|
-callback set_state(State::pubsubState()) ->
|
||||||
@ -224,30 +179,32 @@
|
|||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_items(NodeIdx :: nodeIdx(),
|
-callback get_items(NodeIdx :: nodeIdx(),
|
||||||
JID :: jid(),
|
JID :: jid(),
|
||||||
AccessModel :: accessModel(),
|
AccessModel :: accessModel(),
|
||||||
Presence_Subscription :: boolean(),
|
Presence_Subscription :: boolean(),
|
||||||
RosterGroup :: boolean(),
|
RosterGroup :: boolean(),
|
||||||
SubId :: subId()) ->
|
SubId :: subId(),
|
||||||
{result, [pubsubItem()]} |
|
RSM :: none | rsm_in()) ->
|
||||||
|
{result, {[pubsubItem()], none | rsm_out()}} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_items(NodeIdx :: nodeIdx(),
|
-callback get_items(NodeIdx :: nodeIdx(),
|
||||||
From :: jid()) ->
|
From :: jid(),
|
||||||
{result, [pubsubItem()]}.
|
RSM :: none | rsm_in()) ->
|
||||||
|
{result, {[pubsubItem()], none | rsm_out()}}.
|
||||||
|
|
||||||
-callback get_item(NodeIdx :: nodeIdx(),
|
-callback get_item(NodeIdx :: nodeIdx(),
|
||||||
ItemId :: itemId(),
|
ItemId :: itemId(),
|
||||||
JID :: jid(),
|
JID :: jid(),
|
||||||
AccessModel :: accessModel(),
|
AccessModel :: accessModel(),
|
||||||
PresenceSubscription :: boolean(),
|
PresenceSubscription :: boolean(),
|
||||||
RosterGroup :: boolean(),
|
RosterGroup :: boolean(),
|
||||||
SubId :: subId()) ->
|
SubId :: subId()) ->
|
||||||
{result, pubsubItem()} |
|
{result, pubsubItem()} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_item(NodeIdx :: nodeIdx(),
|
-callback get_item(NodeIdx :: nodeIdx(),
|
||||||
ItemId :: itemId()) ->
|
ItemId :: itemId()) ->
|
||||||
{result, pubsubItem()} |
|
{result, pubsubItem()} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
@ -256,8 +213,8 @@
|
|||||||
% | {error, _}.
|
% | {error, _}.
|
||||||
|
|
||||||
-callback get_item_name(Host :: host(),
|
-callback get_item_name(Host :: host(),
|
||||||
ServerHost :: binary(),
|
ServerHost :: binary(),
|
||||||
Node :: nodeId()) ->
|
Node :: nodeId()) ->
|
||||||
itemId().
|
itemId().
|
||||||
|
|
||||||
-callback node_to_path(Node :: nodeId()) ->
|
-callback node_to_path(Node :: nodeId()) ->
|
||||||
|
@ -32,49 +32,31 @@
|
|||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-type(host() :: mod_pubsub:host()
|
-type(host() :: mod_pubsub:host()).
|
||||||
| mod_pubsub_odbc:host()
|
-type(nodeId() :: mod_pubsub:nodeId()).
|
||||||
).
|
-type(nodeIdx() :: mod_pubsub:nodeIdx()).
|
||||||
|
-type(pubsubNode() :: mod_pubsub:pubsubNode()).
|
||||||
-type(nodeId() :: mod_pubsub:nodeId()
|
-type(nodeOptions() :: mod_pubsub:nodeOptions()).
|
||||||
| 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()
|
|
||||||
).
|
|
||||||
|
|
||||||
-callback init(Host :: host(),
|
-callback init(Host :: host(),
|
||||||
ServerHost :: binary(),
|
ServerHost :: binary(),
|
||||||
Opts :: [any()]) -> atom().
|
Opts :: [any()]) -> atom().
|
||||||
|
|
||||||
-callback terminate(Host :: host(), ServerHost :: binary()) -> atom().
|
-callback terminate(Host :: host(), ServerHost :: binary()) -> atom().
|
||||||
|
|
||||||
-callback options() -> nodeOptions().
|
-callback options() -> nodeOptions().
|
||||||
|
|
||||||
-callback set_node(PubsubNode :: pubsubNode()) ->
|
-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(),
|
-callback get_node(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: jid()) ->
|
From :: jid()) ->
|
||||||
pubsubNode() |
|
pubsubNode() |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_node(Host :: host(),
|
-callback get_node(Host :: host(),
|
||||||
NodeId :: nodeId()) ->
|
NodeId :: nodeId()) ->
|
||||||
pubsubNode() |
|
pubsubNode() |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
@ -83,42 +65,43 @@
|
|||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_nodes(Host :: host(),
|
-callback get_nodes(Host :: host(),
|
||||||
From :: jid())->
|
From :: jid())->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback get_nodes(Host :: host())->
|
-callback get_nodes(Host :: host())->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback get_parentnodes(Host :: host(),
|
-callback get_parentnodes(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: jid()) ->
|
From :: jid()) ->
|
||||||
[pubsubNode()] |
|
[pubsubNode()] |
|
||||||
{error, xmlel()}.
|
{error, xmlel()}.
|
||||||
|
|
||||||
-callback get_parentnodes_tree(Host :: host(),
|
-callback get_parentnodes_tree(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: jid()) ->
|
From :: jid()) ->
|
||||||
[{0, [pubsubNode(),...]}].
|
[{0, [pubsubNode(),...]}].
|
||||||
|
|
||||||
-callback get_subnodes(Host :: host(),
|
-callback get_subnodes(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: ljid()) ->
|
From :: jid()) ->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback get_subnodes_tree(Host :: host(),
|
-callback get_subnodes_tree(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: ljid()) ->
|
From :: jid()) ->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback create_node(Host :: host(),
|
-callback create_node(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
Type :: binary(),
|
Type :: binary(),
|
||||||
Owner :: jid(),
|
Owner :: jid(),
|
||||||
Options :: nodeOptions(),
|
Options :: nodeOptions(),
|
||||||
Parents :: [nodeId()]) ->
|
Parents :: [nodeId()]) ->
|
||||||
{ok, NodeIdx::nodeIdx()} |
|
{ok, NodeIdx::nodeIdx()} |
|
||||||
{error, xmlel()}.
|
{error, xmlel()} |
|
||||||
|
{error, {virtual, {host(), nodeId()}}}.
|
||||||
|
|
||||||
-callback delete_node(Host :: host(),
|
-callback delete_node(Host :: host(),
|
||||||
NodeId :: nodeId()) ->
|
NodeId :: nodeId()) ->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
7347
src/mod_pubsub.erl
7347
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).
|
|
@ -4,58 +4,45 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_buddy).
|
-module(node_buddy).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -64,121 +51,127 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, true},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, true},
|
||||||
{access_model, presence}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, never},
|
{access_model, presence},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, false}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
[<<"create-nodes">>,
|
||||||
<<"delete-items">>, <<"instant-nodes">>, <<"item-ids">>,
|
<<"delete-nodes">>,
|
||||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
<<"delete-items">>,
|
||||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
<<"instant-nodes">>,
|
||||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
<<"item-ids">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"subscription-notifications">>].
|
<<"persistent-items">>,
|
||||||
|
<<"publish">>,
|
||||||
|
<<"purge-nodes">>,
|
||||||
|
<<"retract-items">>,
|
||||||
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
|
<<"subscribe">>,
|
||||||
|
<<"subscription-notifications">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_hometree:create_node_permission(Host, ServerHost,
|
|
||||||
Node, ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeId, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeId, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeId).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeId, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeId, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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,61 +1,48 @@
|
|||||||
%%% ====================================================================
|
%% ====================================================================
|
||||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
%%% ``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
|
%%% 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
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_club).
|
-module(node_club).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -64,121 +51,126 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, true},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, true},
|
||||||
{access_model, authorize}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, never},
|
{access_model, authorize},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, false}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
[<<"create-nodes">>,
|
||||||
<<"delete-items">>, <<"instant-nodes">>,
|
<<"delete-nodes">>,
|
||||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
<<"delete-items">>,
|
||||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
<<"instant-nodes">>,
|
||||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
<<"persistent-items">>,
|
||||||
<<"subscription-notifications">>].
|
<<"publish">>,
|
||||||
|
<<"purge-nodes">>,
|
||||||
|
<<"retract-items">>,
|
||||||
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
|
<<"subscribe">>,
|
||||||
|
<<"subscription-notifications">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_hometree:create_node_permission(Host, ServerHost,
|
|
||||||
Node, ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeId, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeId, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeId).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeId, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeId, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
|
%%%
|
||||||
%%% @author Brian Cully <bjc@kublai.com>
|
%%% @author Brian Cully <bjc@kublai.com>
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_dag).
|
-module(node_dag).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('bjc@kublai.com').
|
-author('bjc@kublai.com').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_node).
|
|
||||||
|
|
||||||
%% API definition
|
|
||||||
-export([init/3, terminate/2, options/0, features/0,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -51,113 +49,108 @@ options() ->
|
|||||||
features() ->
|
features() ->
|
||||||
[<<"multi-collection">> | node_hometree:features()].
|
[<<"multi-collection">> | node_hometree:features()].
|
||||||
|
|
||||||
create_node_permission(_Host, _ServerHost, _Node,
|
create_node_permission(_Host, _ServerHost, _Node, _ParentNode, _Owner, _Access) ->
|
||||||
_ParentNode, _Owner, _Access) ->
|
|
||||||
{result, true}.
|
{result, true}.
|
||||||
|
|
||||||
create_node(NodeID, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeID, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeID, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeID, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeID, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeID, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeID, Publisher, Model, MaxItems, ItemID,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
case nodetree_dag:get_node(Nidx) of
|
||||||
case nodetree_dag:get_node(NodeID) of
|
#pubsub_node{options = Options} ->
|
||||||
#pubsub_node{options = Options} ->
|
case find_opt(node_type, Options) of
|
||||||
case find_opt(node_type, Options) of
|
collection ->
|
||||||
collection ->
|
{error,
|
||||||
{error,
|
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)};
|
||||||
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)};
|
_ ->
|
||||||
_ ->
|
node_hometree:publish_item(Nidx, Publisher, Model,
|
||||||
node_hometree:publish_item(NodeID, Publisher, Model,
|
MaxItems, ItemId, Payload)
|
||||||
MaxItems, ItemID, Payload)
|
end;
|
||||||
end;
|
Err -> Err
|
||||||
Err -> Err
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
find_opt(_, []) -> false;
|
find_opt(_, []) -> false;
|
||||||
find_opt(Option, [{Option, Value} | _]) -> Value;
|
find_opt(Option, [{Option, Value} | _]) -> Value;
|
||||||
find_opt(Option, [_ | T]) -> find_opt(Option, T).
|
find_opt(Option, [_ | T]) -> find_opt(Option, T).
|
||||||
|
|
||||||
remove_extra_items(NodeID, MaxItems, ItemIDs) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeID, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIDs).
|
|
||||||
|
|
||||||
delete_item(NodeID, Publisher, PublishModel, ItemID) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeID, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemID).
|
|
||||||
|
|
||||||
purge_node(NodeID, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeID, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeID) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeID).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeID, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeID, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeID, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeID, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeID) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeID).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeID, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeID, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeID, Owner, Subscription, SubID) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeID, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubID).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeID, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeID, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeID, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubID) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeID, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubID).
|
|
||||||
|
|
||||||
get_item(NodeID, ItemID) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeID, ItemID).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeID, ItemID, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubID) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeID, ItemID, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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).
|
||||||
|
@ -4,56 +4,51 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_dispatch).
|
-module(node_dispatch).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_node).
|
|
||||||
|
|
||||||
%%% @doc <p>The <strong>{@module}</strong> module is a PubSub plugin whose
|
%%% @doc <p>The <strong>{@module}</strong> module is a PubSub plugin whose
|
||||||
%%% goal is to republished each published item to all its children.</p>
|
%%% 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
|
%%% <p>Users cannot subscribe to this node, but are supposed to subscribe to
|
||||||
%%% its children.</p>
|
%%% its children.</p>
|
||||||
%%% This module can not work with virtual nodetree
|
%%% This module can not work with virtual nodetree
|
||||||
|
|
||||||
%% API definition
|
|
||||||
-export([init/3, terminate/2, options/0, features/0,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -62,115 +57,129 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, true},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, true},
|
||||||
{access_model, open}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, never},
|
{access_model, presence},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, false}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
[<<"create-nodes">>,
|
||||||
<<"instant-nodes">>, <<"outcast-affiliation">>,
|
<<"delete-nodes">>,
|
||||||
<<"persistent-items">>, <<"publish">>,
|
<<"instant-nodes">>,
|
||||||
<<"retrieve-items">>].
|
<<"outcast-affiliation">>,
|
||||||
|
<<"persistent-items">>,
|
||||||
|
<<"publish">>,
|
||||||
|
<<"retrieve-items">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_hometree:create_node_permission(Host, ServerHost,
|
|
||||||
Node, ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Nodes) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Nodes).
|
||||||
|
|
||||||
subscribe_node(_NodeId, _Sender, _Subscriber,
|
subscribe_node(_Nidx, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription,
|
||||||
_AccessModel, _SendLast, _PresenceSubscription,
|
_RosterGroup, _Options) ->
|
||||||
_RosterGroup, _Options) ->
|
|
||||||
{error, ?ERR_FORBIDDEN}.
|
{error, ?ERR_FORBIDDEN}.
|
||||||
|
|
||||||
unsubscribe_node(_NodeId, _Sender, _Subscriber,
|
unsubscribe_node(_Nidx, _Sender, _Subscriber, _SubId) ->
|
||||||
_SubID) ->
|
|
||||||
{error, ?ERR_FORBIDDEN}.
|
{error, ?ERR_FORBIDDEN}.
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
case nodetree_tree:get_node(Nidx) of
|
||||||
lists:foreach(fun (SubNode) ->
|
#pubsub_node{nodeid = {Host, Node}} ->
|
||||||
node_hometree:publish_item(SubNode#pubsub_node.id,
|
lists:foreach(fun (SubNode) ->
|
||||||
Publisher, Model, MaxItems,
|
node_hometree:publish_item(SubNode#pubsub_node.id,
|
||||||
ItemId, Payload)
|
Publisher, PublishModel, MaxItems,
|
||||||
end,
|
ItemId, Payload)
|
||||||
nodetree_tree:get_subnodes(NodeId, Publisher,
|
end,
|
||||||
Publisher)).
|
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, []}}.
|
{result, {ItemIds, []}}.
|
||||||
|
|
||||||
delete_item(_NodeId, _Publisher, _PublishModel,
|
delete_item(_Nidx, _Publisher, _PublishModel, _ItemId) ->
|
||||||
_ItemId) ->
|
|
||||||
{error, ?ERR_ITEM_NOT_FOUND}.
|
{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) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(_Host, _Owner) -> {result, []}.
|
get_entity_subscriptions(_Host, _Owner) ->
|
||||||
|
{result, []}.
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(_NodeId, _Owner) -> {result, []}.
|
get_subscriptions(_Nidx, _Owner) ->
|
||||||
|
{result, []}.
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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).
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
@ -25,162 +25,156 @@
|
|||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_flat).
|
-module(node_flat).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_node).
|
|
||||||
|
|
||||||
%% API definition
|
|
||||||
-export([init/3, terminate/2, options/0, features/0,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
node_hometree: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) ->
|
terminate(Host, ServerHost) ->
|
||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
node_hometree:options().
|
||||||
{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() -> node_hometree:features().
|
features() ->
|
||||||
|
node_hometree:features().
|
||||||
|
|
||||||
%% use same code as node_hometree, but do not limite node to
|
%% use same code as node_hometree, but do not limite node to
|
||||||
%% the home/localhost/user/... hierarchy
|
%% the home/localhost/user/... hierarchy
|
||||||
%% any node is allowed
|
%% any node is allowed
|
||||||
create_node_permission(Host, ServerHost, _Node,
|
create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
|
||||||
_ParentNode, Owner, Access) ->
|
|
||||||
LOwner = jlib:jid_tolower(Owner),
|
LOwner = jlib:jid_tolower(Owner),
|
||||||
Allowed = case LOwner of
|
Allowed = case LOwner of
|
||||||
{<<"">>, Host, <<"">>} ->
|
{<<"">>, Host, <<"">>} ->
|
||||||
true; % pubsub service always allowed
|
true; % pubsub service always allowed
|
||||||
_ ->
|
_ ->
|
||||||
acl:match_rule(ServerHost, Access, LOwner) =:= allow
|
acl:match_rule(ServerHost, Access, LOwner) =:= allow
|
||||||
end,
|
end,
|
||||||
{result, Allowed}.
|
{result, Allowed}.
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
AccessModel, SendLast, PresenceSubscription,
|
||||||
RosterGroup, Options).
|
RosterGroup, Options).
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeId, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeId, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeId).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeId, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeId, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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) ->
|
path_to_node(Path) ->
|
||||||
case Path of
|
case Path of
|
||||||
% default slot
|
% default slot
|
||||||
[Node] -> iolist_to_binary(Node);
|
[Node] -> iolist_to_binary(Node);
|
||||||
% handle old possible entries, used when migrating database content to new format
|
% handle old possible entries, used when migrating database content to new format
|
||||||
[Node | _] when is_binary(Node) ->
|
[Node | _] when is_binary(Node) ->
|
||||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||||
% default case (used by PEP for example)
|
% default case (used by PEP for example)
|
||||||
_ -> iolist_to_binary(Path)
|
_ -> iolist_to_binary(Path)
|
||||||
end.
|
end.
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
@ -25,30 +25,25 @@
|
|||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_flat_odbc).
|
-module(node_flat_odbc).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_node).
|
|
||||||
|
|
||||||
%% API definition
|
|
||||||
-export([init/3, terminate/2, options/0, features/0,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_entity_subscriptions_for_send_last/2,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_node_subscriptions/1, get_subscriptions/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_subscriptions/4, get_pending_nodes/2, get_states/1,
|
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||||
get_state/2, set_state/1, get_items/7, get_items/6,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
get_items/3, get_items/2, get_item/7, get_item/2,
|
path_to_node/1,
|
||||||
set_item/1, get_item_name/3, get_last_items/3,
|
get_entity_subscriptions_for_send_last/2, get_last_items/3]).
|
||||||
node_to_path/1, path_to_node/1]).
|
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree_odbc:init(Host, ServerHost, Opts).
|
node_hometree_odbc:init(Host, ServerHost, Opts).
|
||||||
@ -57,157 +52,115 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree_odbc:terminate(Host, ServerHost).
|
node_hometree_odbc:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true},
|
[{odbc, true}, {rsm, true} | node_flat:options()].
|
||||||
{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}].
|
|
||||||
|
|
||||||
features() -> node_hometree_odbc:features().
|
features() ->
|
||||||
|
[<<"rsm">> | node_flat:features()].
|
||||||
|
|
||||||
%% use same code as node_hometree_odbc, but do not limite node to
|
%% use same code as node_hometree_odbc, but do not limite node to
|
||||||
%% the home/localhost/user/... hierarchy
|
%% the home/localhost/user/... hierarchy
|
||||||
%% any node is allowed
|
%% any node is allowed
|
||||||
create_node_permission(Host, ServerHost, _Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
_ParentNode, Owner, Access) ->
|
node_flat: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(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree_odbc:create_node(NodeId, Owner).
|
node_hometree_odbc:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree_odbc:delete_node(Removed).
|
node_hometree_odbc:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree_odbc:subscribe_node(NodeId, Sender,
|
node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
Subscriber, AccessModel, SendLast,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
PresenceSubscription, RosterGroup,
|
|
||||||
Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree_odbc:unsubscribe_node(NodeId, Sender,
|
node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree_odbc:publish_item(NodeId, Publisher,
|
|
||||||
Model, MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree_odbc:remove_extra_items(NodeId, MaxItems,
|
node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree_odbc:delete_item(NodeId, Publisher,
|
node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree_odbc:purge_node(NodeId, Owner).
|
node_hometree_odbc:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree_odbc:get_entity_affiliations(Host, Owner).
|
node_hometree_odbc:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree_odbc:get_node_affiliations(NodeId).
|
node_hometree_odbc:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree_odbc:get_affiliation(NodeId, Owner).
|
node_hometree_odbc:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree_odbc:set_affiliation(NodeId, Owner,
|
node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree_odbc:get_entity_subscriptions(Host,
|
node_hometree_odbc:get_entity_subscriptions(Host, Owner).
|
||||||
Owner).
|
|
||||||
|
|
||||||
get_entity_subscriptions_for_send_last(Host, Owner) ->
|
get_entity_subscriptions_for_send_last(Host, Owner) ->
|
||||||
node_hometree_odbc:get_entity_subscriptions_for_send_last(Host,
|
node_hometree_odbc:get_entity_subscriptions_for_send_last(Host, Owner).
|
||||||
Owner).
|
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree_odbc:get_node_subscriptions(NodeId).
|
node_hometree_odbc:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree_odbc:get_subscriptions(NodeId, Owner).
|
node_hometree_odbc:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree_odbc:set_subscriptions(NodeId, Owner,
|
node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
||||||
|
|
||||||
get_states(NodeId) ->
|
get_states(Nidx) ->
|
||||||
node_hometree_odbc:get_states(NodeId).
|
node_hometree_odbc:get_states(Nidx).
|
||||||
|
|
||||||
get_state(NodeId, JID) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree_odbc:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree_odbc:get_items(NodeId, From).
|
node_hometree_odbc:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, From, RSM) ->
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
node_hometree_odbc:get_items(NodeId, From, RSM).
|
node_hometree_odbc:get_items(Nidx, JID, AccessModel,
|
||||||
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_item(Nidx, ItemId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree_odbc:get_item(Nidx, ItemId).
|
||||||
get_items(NodeId, JID, AccessModel,
|
|
||||||
PresenceSubscription, RosterGroup, SubId, none).
|
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId, RSM) ->
|
node_hometree_odbc:get_item(Nidx, ItemId, JID,
|
||||||
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
|
AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
set_item(Item) ->
|
||||||
node_hometree_odbc:get_item(NodeId, ItemId).
|
node_hometree_odbc:set_item(Item).
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
get_item_name(Host, Node, Id) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree_odbc:get_item_name(Host, Node, Id).
|
node_hometree_odbc:get_item_name(Host, Node, Id).
|
||||||
|
|
||||||
get_last_items(NodeId, From, Count) ->
|
get_last_items(Nidx, From, Count) ->
|
||||||
node_hometree_odbc:get_last_items(NodeId, 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) ->
|
path_to_node(Path) ->
|
||||||
case Path of
|
case Path of
|
||||||
% default slot
|
% default slot
|
||||||
[Node] -> iolist_to_binary(Node);
|
[Node] -> iolist_to_binary(Node);
|
||||||
% handle old possible entries, used when migrating database content to new format
|
% handle old possible entries, used when migrating database content to new format
|
||||||
[Node | _] when is_binary(Node) ->
|
[Node | _] when is_binary(Node) ->
|
||||||
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
iolist_to_binary(str:join([<<"">> | Path], <<"/">>));
|
||||||
% default case (used by PEP for example)
|
% default case (used by PEP for example)
|
||||||
_ -> iolist_to_binary(Path)
|
_ -> iolist_to_binary(Path)
|
||||||
end.
|
end.
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
223
src/node_mb.erl
223
src/node_mb.erl
@ -4,62 +4,54 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @copyright 2006-2015 ProcessOne
|
%%% @copyright 2006-2015 ProcessOne
|
||||||
%%% @author Eric Cestari <eric@ohmforce.com>
|
%%% @author Eric Cestari <eric@ohmforce.com>
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @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.
|
%%% @doc The module <strong>{@module}</strong> is the pep microblog PubSub plugin.
|
||||||
%%% <p> To be used, mod_pubsub must be configured :
|
%%% <p> To be used, mod_pubsub must be configured :
|
||||||
%%% {mod_pubsub, [ % requires mod_caps
|
%%% {mod_pubsub, [ % requires mod_caps
|
||||||
%%% {access_createnode, pubsub_createnode},
|
%%% {access_createnode, pubsub_createnode},
|
||||||
%%% {plugins, ["default", "pep","mb"]},
|
%%% {plugins, ["default", "pep","mb"]},
|
||||||
%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]}
|
%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]}
|
||||||
%%% ]},
|
%%% ]},
|
||||||
%%% </p>
|
%%% </p>
|
||||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_pep:init(Host, ServerHost, Opts).
|
node_pep:init(Host, ServerHost, Opts).
|
||||||
@ -68,124 +60,127 @@ terminate(Host, ServerHost) ->
|
|||||||
node_pep:terminate(Host, ServerHost), ok.
|
node_pep:terminate(Host, ServerHost), ok.
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, false},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, false},
|
||||||
{access_model, presence}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, on_sub_and_presence},
|
{access_model, presence},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, true}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, %*
|
[<<"create-nodes">>,
|
||||||
<<"auto-create">>, %*
|
<<"auto-create">>,
|
||||||
<<"auto-subscribe">>, %*
|
<<"auto-subscribe">>,
|
||||||
<<"delete-nodes">>, %*
|
<<"delete-nodes">>,
|
||||||
<<"delete-items">>, %*
|
<<"delete-items">>,
|
||||||
<<"filtered-notifications">>, %*
|
<<"filtered-notifications">>,
|
||||||
<<"modify-affiliations">>, <<"outcast-affiliation">>,
|
<<"modify-affiliations">>,
|
||||||
<<"persistent-items">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"publish">>, %*
|
<<"persistent-items">>,
|
||||||
<<"purge-nodes">>, <<"retract-items">>,
|
<<"publish">>,
|
||||||
<<"retrieve-affiliations">>,
|
<<"purge-nodes">>,
|
||||||
<<"retrieve-items">>, %*
|
<<"retract-items">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>].
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
|
<<"subscribe">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_pep:create_node_permission(Host, ServerHost, Node,
|
|
||||||
ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_pep:create_node(NodeId, 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,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_pep:subscribe_node(NodeId, Sender, Subscriber,
|
node_pep:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_pep:unsubscribe_node(NodeId, Sender, Subscriber,
|
node_pep:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_pep:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_pep:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_pep:remove_extra_items(NodeId, MaxItems, ItemIds).
|
node_pep:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_pep:delete_item(NodeId, Publisher, PublishModel,
|
node_pep:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_pep:purge_node(NodeId, Owner).
|
node_pep:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_pep:get_entity_affiliations(Host, Owner).
|
node_pep:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_pep:get_node_affiliations(NodeId).
|
node_pep:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_pep:get_affiliation(NodeId, Owner).
|
node_pep:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_pep:set_affiliation(NodeId, Owner, Affiliation).
|
node_pep:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_pep:get_entity_subscriptions(Host, Owner).
|
node_pep:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_pep:get_node_subscriptions(NodeId).
|
node_pep:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_pep:get_subscriptions(NodeId, Owner).
|
node_pep:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_pep:set_subscriptions(NodeId, Owner, Subscription,
|
node_pep:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_pep:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_pep:get_items(NodeId, From).
|
node_pep:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_pep:get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
node_pep:get_items(NodeId, JID, AccessModel,
|
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_pep:get_item(NodeId, ItemId).
|
node_pep:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_pep:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_pep:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_pep: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).
|
||||||
|
563
src/node_pep.erl
563
src/node_pep.erl
@ -4,20 +4,19 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
@ -25,35 +24,29 @@
|
|||||||
%%% @end
|
%%% @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.
|
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
|
||||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
|
%%% <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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts),
|
node_hometree:init(Host, ServerHost, Opts),
|
||||||
@ -63,423 +56,193 @@ init(Host, ServerHost, Opts) ->
|
|||||||
terminate(Host, ServerHost) ->
|
terminate(Host, ServerHost) ->
|
||||||
node_hometree:terminate(Host, ServerHost), ok.
|
node_hometree:terminate(Host, ServerHost), ok.
|
||||||
|
|
||||||
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, false},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, 1}, {subscribe, true},
|
{notify_retract, false},
|
||||||
{access_model, presence}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, false},
|
||||||
{notification_type, headline},
|
{max_items, 1},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, on_sub_and_presence},
|
{access_model, presence},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, true}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, %*
|
[<<"create-nodes">>,
|
||||||
<<"auto-create">>, %*
|
<<"auto-create">>,
|
||||||
<<"auto-subscribe">>, %*
|
<<"auto-subscribe">>,
|
||||||
<<"delete-nodes">>, %*
|
<<"delete-nodes">>,
|
||||||
<<"delete-items">>, %*
|
<<"delete-items">>,
|
||||||
<<"filtered-notifications">>, %*
|
<<"filtered-notifications">>,
|
||||||
<<"modify-affiliations">>, <<"outcast-affiliation">>,
|
<<"modify-affiliations">>,
|
||||||
<<"persistent-items">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"publish">>, %*
|
<<"persistent-items">>,
|
||||||
<<"purge-nodes">>, <<"retract-items">>,
|
<<"publish">>,
|
||||||
<<"retrieve-affiliations">>,
|
<<"purge-nodes">>,
|
||||||
<<"retrieve-items">>, %*
|
<<"retract-items">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>].
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
-spec(create_node_permission/6 ::
|
<<"subscribe">>].
|
||||||
(
|
|
||||||
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) ->
|
create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
|
||||||
LOwner = jlib:jid_tolower(Owner),
|
LOwner = jlib:jid_tolower(Owner),
|
||||||
{User, Server, _Resource} = LOwner,
|
{User, Server, _Resource} = LOwner,
|
||||||
Allowed = case LOwner of
|
Allowed = case LOwner of
|
||||||
{<<"">>, Host, <<"">>} ->
|
{<<"">>, Host, <<"">>} ->
|
||||||
true; % pubsub service always allowed
|
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
|
false
|
||||||
allow ->
|
end
|
||||||
case Host of
|
end,
|
||||||
{User, Server, _} -> true;
|
|
||||||
_ -> false
|
|
||||||
end;
|
|
||||||
E -> ?DEBUG("Create not allowed : ~p~n", [E]), false
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
{result, Allowed}.
|
{result, Allowed}.
|
||||||
|
|
||||||
-spec(create_node/2 ::
|
create_node(Nidx, Owner) ->
|
||||||
(
|
node_hometree:create_node(Nidx, Owner).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
Owner :: jid())
|
|
||||||
-> {result, {default, broadcast}}
|
|
||||||
).
|
|
||||||
create_node(NodeIdx, Owner) ->
|
|
||||||
node_hometree:create_node(NodeIdx, Owner).
|
|
||||||
|
|
||||||
-spec(delete_node/1 ::
|
delete_node(Nodes) ->
|
||||||
(
|
{result, {_, _, Result}} = node_hometree:delete_node(Nodes),
|
||||||
Nodes :: [mod_pubsub:pubsubNode(),...])
|
{result, {[], Result}}.
|
||||||
-> {result,
|
|
||||||
{[],
|
|
||||||
[{mod_pubsub:pubsubNode(),
|
|
||||||
[{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]},...]},...]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).
|
|
||||||
|
|
||||||
delete_node(Removed) ->
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
case node_hometree:delete_node(Removed) of
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
{result, {_, _, Result}} -> {result, {[], Result}};
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
Error -> Error
|
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.
|
end.
|
||||||
|
|
||||||
-spec(subscribe_node/8 ::
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
(
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
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).
|
|
||||||
|
|
||||||
-spec(unsubscribe_node/4 ::
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
(
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
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.
|
|
||||||
|
|
||||||
-spec(publish_item/6 ::
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
(
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
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).
|
|
||||||
|
|
||||||
-spec(remove_extra_items/3 ::
|
purge_node(Nidx, Owner) ->
|
||||||
(
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
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).
|
|
||||||
|
|
||||||
|
get_entity_affiliations(Host, 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) ->
|
|
||||||
{_, D, _} = SubKey = jlib:jid_tolower(Owner),
|
{_, D, _} = SubKey = jlib:jid_tolower(Owner),
|
||||||
SubKey = jlib:jid_tolower(Owner),
|
SubKey = jlib:jid_tolower(Owner),
|
||||||
GenKey = jlib:jid_remove_resource(SubKey),
|
GenKey = jlib:jid_remove_resource(SubKey),
|
||||||
States = mnesia:match_object(#pubsub_state{stateid =
|
States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
|
||||||
{GenKey, '_'},
|
NodeTree = mod_pubsub:tree(Host),
|
||||||
_ = '_'}),
|
Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) ->
|
||||||
NodeTree = case catch
|
case NodeTree:get_node(N) of
|
||||||
ets:lookup(gen_mod:get_module_proc(D, config), nodetree)
|
#pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A} | Acc];
|
||||||
of
|
_ -> Acc
|
||||||
[{nodetree, N}] -> N;
|
end
|
||||||
_ -> nodetree_tree
|
end,
|
||||||
end,
|
[], States),
|
||||||
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}.
|
{result, Reply}.
|
||||||
|
|
||||||
|
|
||||||
-spec(get_node_affiliations/1 ::
|
get_node_affiliations(Nidx) ->
|
||||||
(
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
|
|
||||||
).
|
|
||||||
get_node_affiliations(NodeIdx) ->
|
|
||||||
node_hometree:get_node_affiliations(NodeIdx).
|
|
||||||
|
|
||||||
-spec(get_affiliation/2 ::
|
get_affiliation(Nidx, Owner) ->
|
||||||
(
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
Owner :: jid())
|
|
||||||
-> {result, mod_pubsub:affiliation()}
|
|
||||||
).
|
|
||||||
get_affiliation(NodeIdx, Owner) ->
|
|
||||||
node_hometree:get_affiliation(NodeIdx, Owner).
|
|
||||||
|
|
||||||
-spec(set_affiliation/3 ::
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
(
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
Owner :: ljid(),
|
|
||||||
Affiliation :: mod_pubsub:affiliation())
|
|
||||||
-> ok
|
|
||||||
).
|
|
||||||
set_affiliation(NodeIdx, Owner, Affiliation) ->
|
|
||||||
node_hometree:set_affiliation(NodeIdx, Owner, Affiliation).
|
|
||||||
|
|
||||||
-spec(get_entity_subscriptions/2 ::
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
(
|
|
||||||
Host :: mod_pubsub:hostPEP(),
|
|
||||||
Owner :: jid())
|
|
||||||
-> {result,
|
|
||||||
[{mod_pubsub:pubsubNode(),
|
|
||||||
mod_pubsub:subscription(),
|
|
||||||
mod_pubsub:subId(),
|
|
||||||
ljid()}]
|
|
||||||
}
|
|
||||||
).
|
|
||||||
get_entity_subscriptions(_Host, Owner) ->
|
|
||||||
{U, D, _} = SubKey = jlib:jid_tolower(Owner),
|
{U, D, _} = SubKey = jlib:jid_tolower(Owner),
|
||||||
GenKey = jlib:jid_remove_resource(SubKey),
|
GenKey = jlib:jid_remove_resource(SubKey),
|
||||||
States = case SubKey of
|
States = case SubKey of
|
||||||
GenKey ->
|
GenKey ->
|
||||||
mnesia:match_object(#pubsub_state{stateid =
|
mnesia:match_object(#pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
|
||||||
{{U, D, '_'}, '_'},
|
_ ->
|
||||||
_ = '_'});
|
mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
|
||||||
_ ->
|
++
|
||||||
mnesia:match_object(#pubsub_state{stateid =
|
mnesia:match_object(#pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
|
||||||
{GenKey, '_'},
|
end,
|
||||||
_ = '_'})
|
NodeTree = mod_pubsub:tree(Host),
|
||||||
++
|
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) ->
|
||||||
mnesia:match_object(#pubsub_state{stateid =
|
case NodeTree:get_node(N) of
|
||||||
{SubKey, '_'},
|
#pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
|
||||||
_ = '_'})
|
lists:foldl(fun
|
||||||
end,
|
({subscribed, SubId}, Acc2) ->
|
||||||
NodeTree = case catch
|
[{Node, subscribed, SubId, J} | Acc2];
|
||||||
ets:lookup(gen_mod:get_module_proc(D, config), nodetree)
|
({pending, _SubId}, Acc2) ->
|
||||||
of
|
[{Node, pending, J} | Acc2];
|
||||||
[{nodetree, N}] -> N;
|
(S, Acc2) ->
|
||||||
_ -> nodetree_tree
|
[{Node, S, J} | Acc2]
|
||||||
end,
|
end,
|
||||||
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N},
|
Acc, Ss);
|
||||||
subscriptions = Ss},
|
_ ->
|
||||||
Acc) ->
|
Acc
|
||||||
case NodeTree:get_node(N) of
|
end
|
||||||
#pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
|
end,
|
||||||
lists:foldl(fun
|
[], States),
|
||||||
({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}.
|
{result, Reply}.
|
||||||
|
|
||||||
-spec(get_node_subscriptions/1 ::
|
get_node_subscriptions(Nidx) ->
|
||||||
(
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> {result,
|
|
||||||
[{ljid(), mod_pubsub:subscription(), mod_pubsub:subId()}] |
|
|
||||||
[{ljid(), none},...]
|
|
||||||
}
|
|
||||||
).
|
|
||||||
get_node_subscriptions(NodeIdx) ->
|
|
||||||
node_hometree:get_node_subscriptions(NodeIdx).
|
|
||||||
|
|
||||||
-spec(get_subscriptions/2 ::
|
get_subscriptions(Nidx, Owner) ->
|
||||||
(
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
Owner :: ljid())
|
|
||||||
-> {result, [{mod_pubsub:subscription(), mod_pubsub:subId()}]}
|
|
||||||
).
|
|
||||||
get_subscriptions(NodeIdx, Owner) ->
|
|
||||||
node_hometree:get_subscriptions(NodeIdx, Owner).
|
|
||||||
|
|
||||||
-spec(set_subscriptions/4 ::
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
(
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
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).
|
|
||||||
|
|
||||||
-spec(get_pending_nodes/2 ::
|
|
||||||
(
|
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
|
||||||
Owner :: jid())
|
|
||||||
-> {result, [mod_pubsub:nodeId()]}
|
|
||||||
).
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree:get_pending_nodes(Host, Owner).
|
node_hometree:get_pending_nodes(Host, Owner).
|
||||||
|
|
||||||
-spec(get_states/1 ::
|
get_states(Nidx) ->
|
||||||
(
|
node_hometree:get_states(Nidx).
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> {result, [mod_pubsub:pubsubState()]}
|
|
||||||
).
|
|
||||||
get_states(NodeIdx) -> node_hometree:get_states(NodeIdx).
|
|
||||||
|
|
||||||
-spec(get_state/2 ::
|
get_state(Nidx, JID) ->
|
||||||
(
|
node_hometree:get_state(Nidx, JID).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
JID :: ljid())
|
|
||||||
-> mod_pubsub:pubsubState()
|
|
||||||
).
|
|
||||||
get_state(NodeIdx, JID) ->
|
|
||||||
node_hometree:get_state(NodeIdx, JID).
|
|
||||||
|
|
||||||
-spec(set_state/1 ::
|
set_state(State) ->
|
||||||
(
|
node_hometree:set_state(State).
|
||||||
State::mod_pubsub:pubsubState())
|
|
||||||
-> ok
|
|
||||||
).
|
|
||||||
set_state(State) -> node_hometree:set_state(State).
|
|
||||||
|
|
||||||
-spec(get_items/2 ::
|
get_items(Nidx, From, RSM) ->
|
||||||
(
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
_From :: jid())
|
|
||||||
-> {result, [mod_pubsub:pubsubItem()]}
|
|
||||||
).
|
|
||||||
get_items(NodeIdx, From) ->
|
|
||||||
node_hometree:get_items(NodeIdx, From).
|
|
||||||
|
|
||||||
-spec(get_items/6 ::
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
(
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
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).
|
|
||||||
|
|
||||||
-spec(get_item/2 ::
|
get_item(Nidx, ItemId) ->
|
||||||
(
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
ItemId :: mod_pubsub:itemId())
|
|
||||||
-> {result, mod_pubsub:pubsubItem()}
|
|
||||||
| {error, xmlel()}
|
|
||||||
).
|
|
||||||
get_item(NodeIdx, ItemId) ->
|
|
||||||
node_hometree:get_item(NodeIdx, ItemId).
|
|
||||||
|
|
||||||
-spec(get_item/7 ::
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
(
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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).
|
|
||||||
|
|
||||||
-spec(set_item/1 ::
|
set_item(Item) ->
|
||||||
(
|
node_hometree:set_item(Item).
|
||||||
Item::mod_pubsub:pubsubItem())
|
|
||||||
-> ok
|
|
||||||
).
|
|
||||||
set_item(Item) -> node_hometree:set_item(Item).
|
|
||||||
|
|
||||||
get_item_name(Host, Node, Id) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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
|
%%% 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.
|
%% If not, show a warning message in the ejabberd log file.
|
||||||
complain_if_modcaps_disabled(ServerHost) ->
|
complain_if_modcaps_disabled(ServerHost) ->
|
||||||
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
||||||
false ->
|
false ->
|
||||||
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||||
"of host ~p. This plugin requires mod_caps "
|
"of host ~p. This plugin requires mod_caps "
|
||||||
"to be enabled, but it isn't.",
|
"to be enabled, but it isn't.",
|
||||||
[ServerHost]);
|
[ServerHost]);
|
||||||
true -> ok
|
true -> ok
|
||||||
end.
|
end.
|
||||||
|
@ -4,20 +4,19 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
@ -25,39 +24,30 @@
|
|||||||
%%% @end
|
%%% @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.
|
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
|
||||||
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
|
%%% <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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_entity_subscriptions_for_send_last/2,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_node_subscriptions/1, get_subscriptions/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_subscriptions/4, get_pending_nodes/2, get_states/1,
|
set_state/1, get_items/7, get_items/3, get_item/7,
|
||||||
get_state/2, set_state/1, get_items/7, get_items/6,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
get_items/3, get_items/2, get_item/7, get_item/2,
|
path_to_node/1,
|
||||||
set_item/1, get_item_name/3, get_last_items/3,
|
get_entity_subscriptions_for_send_last/2, get_last_items/3]).
|
||||||
node_to_path/1, path_to_node/1]).
|
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree_odbc:init(Host, ServerHost, Opts),
|
node_hometree_odbc:init(Host, ServerHost, Opts),
|
||||||
@ -67,362 +57,183 @@ init(Host, ServerHost, Opts) ->
|
|||||||
terminate(Host, ServerHost) ->
|
terminate(Host, ServerHost) ->
|
||||||
node_hometree_odbc:terminate(Host, ServerHost), ok.
|
node_hometree_odbc:terminate(Host, ServerHost), ok.
|
||||||
|
|
||||||
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
|
|
||||||
options() ->
|
options() ->
|
||||||
[{odbc, true},
|
[{odbc, true}, {rsm, true} | node_pep: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}].
|
|
||||||
|
|
||||||
-spec(features/0 :: () -> Features::[binary(),...]).
|
|
||||||
features() ->
|
features() ->
|
||||||
[<<"create-nodes">>, %*
|
[<<"rsm">> | node_pep:features()].
|
||||||
<<"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 ::
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
(
|
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
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, _NodeId, _ParentNode, Owner, Access) ->
|
create_node(Nidx, Owner) ->
|
||||||
LOwner = jlib:jid_tolower(Owner),
|
node_hometree_odbc:create_node(Nidx, Owner),
|
||||||
{User, Server, _Resource} = LOwner,
|
{result, {default, broadcast}}.
|
||||||
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}.
|
|
||||||
|
|
||||||
-spec(create_node/2 ::
|
delete_node(Nodes) ->
|
||||||
(
|
{result, {_, _, Result}} = node_hometree_odbc:delete_node(Nodes),
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
{result, {[], Result}}.
|
||||||
Owner :: jid())
|
|
||||||
-> {result, []}
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
).
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
create_node(NodeIdx, Owner) ->
|
node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
case node_hometree_odbc:create_node(NodeIdx, Owner) of
|
PresenceSubscription, RosterGroup, Options).
|
||||||
{result, _} -> {result, []};
|
|
||||||
Error -> Error
|
|
||||||
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
|
case node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
|
||||||
|
{error, Error} -> {error, Error};
|
||||||
|
{result, _} -> {result, []}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(delete_node/1 ::
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
(
|
node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
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.
|
|
||||||
|
|
||||||
-spec(subscribe_node/8 ::
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
(
|
node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
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).
|
|
||||||
|
|
||||||
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
|
node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
|
|
||||||
-spec(unsubscribe_node/4 ::
|
purge_node(Nidx, Owner) ->
|
||||||
(
|
node_hometree_odbc:purge_node(Nidx, Owner).
|
||||||
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.
|
|
||||||
|
|
||||||
-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) ->
|
get_entity_affiliations(_Host, Owner) ->
|
||||||
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||||
node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner).
|
node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner).
|
||||||
|
|
||||||
-spec(get_node_affiliations/1 ::
|
get_node_affiliations(Nidx) ->
|
||||||
(
|
node_hometree_odbc:get_node_affiliations(Nidx).
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
|
|
||||||
).
|
|
||||||
get_node_affiliations(NodeIdx) ->
|
|
||||||
node_hometree_odbc:get_node_affiliations(NodeIdx).
|
|
||||||
|
|
||||||
-spec(get_affiliation/2 ::
|
get_affiliation(Nidx, Owner) ->
|
||||||
(
|
node_hometree_odbc:get_affiliation(Nidx, Owner).
|
||||||
NodeIdx :: mod_pubsub:nodeIdx(),
|
|
||||||
Owner :: ljid())
|
|
||||||
-> {result, mod_pubsub:affiliation()}
|
|
||||||
).
|
|
||||||
get_affiliation(NodeIdx, Owner) ->
|
|
||||||
node_hometree_odbc:get_affiliation(NodeIdx, Owner).
|
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree_odbc:set_affiliation(NodeId, Owner, Affiliation).
|
node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
|
|
||||||
get_entity_subscriptions(_Host, Owner) ->
|
get_entity_subscriptions(_Host, Owner) ->
|
||||||
SubKey = jlib:jid_tolower(Owner),
|
SubKey = jlib:jid_tolower(Owner),
|
||||||
GenKey = jlib:jid_remove_resource(SubKey),
|
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),
|
SJ = node_hometree_odbc:encode_jid(SubKey),
|
||||||
GJ = node_hometree_odbc:encode_jid(GenKey),
|
GJ = node_hometree_odbc:encode_jid(GenKey),
|
||||||
Query = case SubKey of
|
Query = case SubKey of
|
||||||
GenKey ->
|
GenKey ->
|
||||||
[<<"select host, node, type, i.nodeid, jid, "
|
[<<"select host, node, type, i.nodeid, jid, "
|
||||||
"subscriptions from pubsub_state i, pubsub_nod"
|
"subscriptions from pubsub_state i, pubsub_node n "
|
||||||
"e n where i.nodeid = n.nodeid and jid "
|
"where i.nodeid = n.nodeid and jid "
|
||||||
"like '">>,
|
"like '">>, GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||||
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
_ ->
|
||||||
_ ->
|
[<<"select host, node, type, i.nodeid, jid, "
|
||||||
[<<"select host, node, type, i.nodeid, jid, "
|
"subscriptions from pubsub_state i, pubsub_node n "
|
||||||
"subscriptions from pubsub_state i, pubsub_nod"
|
"where i.nodeid = n.nodeid and jid "
|
||||||
"e n where i.nodeid = n.nodeid and jid "
|
"in ('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
|
||||||
"in ('">>,
|
end,
|
||||||
SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host,
|
|
||||||
<<"';">>]
|
|
||||||
end,
|
|
||||||
Reply = case catch ejabberd_odbc:sql_query_t(Query) of
|
Reply = case catch ejabberd_odbc:sql_query_t(Query) of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>,
|
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
|
||||||
<<"jid">>, <<"subscriptions">>],
|
RItems} ->
|
||||||
RItems} ->
|
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
O = node_hometree_odbc:decode_jid(H),
|
||||||
O = node_hometree_odbc:decode_jid(H),
|
Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
|
||||||
Node = nodetree_tree_odbc:raw_to_node(O,
|
{Node,
|
||||||
[N,
|
node_hometree_odbc:decode_subscriptions(S),
|
||||||
<<"">>,
|
node_hometree_odbc:decode_jid(J)}
|
||||||
T,
|
end,
|
||||||
I]),
|
RItems);
|
||||||
{Node,
|
_ ->
|
||||||
node_hometree_odbc:decode_subscriptions(S),
|
[]
|
||||||
node_hometree_odbc:decode_jid(J)}
|
end,
|
||||||
end,
|
|
||||||
RItems);
|
|
||||||
_ -> []
|
|
||||||
end,
|
|
||||||
{result, Reply}.
|
{result, Reply}.
|
||||||
|
|
||||||
get_entity_subscriptions_for_send_last(_Host, Owner) ->
|
get_entity_subscriptions_for_send_last(_Host, Owner) ->
|
||||||
SubKey = jlib:jid_tolower(Owner),
|
SubKey = jlib:jid_tolower(Owner),
|
||||||
GenKey = jlib:jid_remove_resource(SubKey),
|
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),
|
SJ = node_hometree_odbc:encode_jid(SubKey),
|
||||||
GJ = node_hometree_odbc:encode_jid(GenKey),
|
GJ = node_hometree_odbc:encode_jid(GenKey),
|
||||||
Query = case SubKey of
|
Query = case SubKey of
|
||||||
GenKey ->
|
GenKey ->
|
||||||
[<<"select host, node, type, i.nodeid, jid, "
|
[<<"select host, node, type, i.nodeid, jid, "
|
||||||
"subscriptions from pubsub_state i, pubsub_nod"
|
"subscriptions from pubsub_state i, pubsub_node n, "
|
||||||
"e n, pubsub_node_option o where i.nodeid "
|
"pubsub_node_option o where i.nodeid = n.nodeid "
|
||||||
"= n.nodeid and n.nodeid = o.nodeid and "
|
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
|
||||||
"name='send_last_published_item' and "
|
"val='on_sub_and_presence' and jid like '">>,
|
||||||
"val='on_sub_and_presence' and jid like "
|
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
||||||
"'">>,
|
_ ->
|
||||||
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
|
[<<"select host, node, type, i.nodeid, jid, "
|
||||||
_ ->
|
"subscriptions from pubsub_state i, pubsub_node n, "
|
||||||
[<<"select host, node, type, i.nodeid, jid, "
|
"pubsub_node_option o where i.nodeid = n.nodeid "
|
||||||
"subscriptions from pubsub_state i, pubsub_nod"
|
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
|
||||||
"e n, pubsub_node_option o where i.nodeid "
|
"val='on_sub_and_presence' and jid in ",
|
||||||
"= n.nodeid and n.nodeid = o.nodeid and "
|
"('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
|
||||||
"name='send_last_published_item' and "
|
end,
|
||||||
"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
|
Reply = case catch ejabberd_odbc:sql_query_t(Query) of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>,
|
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
|
||||||
<<"jid">>, <<"subscriptions">>],
|
RItems} ->
|
||||||
RItems} ->
|
lists:map(fun ([H, N, T, I, J, S]) ->
|
||||||
lists:map(fun ([H, N, T, I, J, S]) ->
|
O = node_hometree_odbc:decode_jid(H),
|
||||||
O = node_hometree_odbc:decode_jid(H),
|
Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
|
||||||
Node = nodetree_tree_odbc:raw_to_node(O,
|
{Node,
|
||||||
[N,
|
node_hometree_odbc:decode_subscriptions(S),
|
||||||
<<"">>,
|
node_hometree_odbc:decode_jid(J)}
|
||||||
T,
|
end,
|
||||||
I]),
|
RItems);
|
||||||
{Node,
|
_ ->
|
||||||
node_hometree_odbc:decode_subscriptions(S),
|
[]
|
||||||
node_hometree_odbc:decode_jid(J)}
|
end,
|
||||||
end,
|
|
||||||
RItems);
|
|
||||||
_ -> []
|
|
||||||
end,
|
|
||||||
{result, Reply}.
|
{result, Reply}.
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree_odbc:get_node_subscriptions(NodeId).
|
node_hometree_odbc:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree_odbc:get_subscriptions(NodeId, Owner).
|
node_hometree_odbc:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree_odbc:set_subscriptions(NodeId, Owner,
|
node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
node_hometree_odbc:get_pending_nodes(Host, Owner).
|
||||||
|
|
||||||
get_states(NodeId) ->
|
get_states(Nidx) ->
|
||||||
node_hometree_odbc:get_states(NodeId).
|
node_hometree_odbc:get_states(Nidx).
|
||||||
|
|
||||||
get_state(NodeId, JID) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree_odbc:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree_odbc:get_items(NodeId, From).
|
node_hometree_odbc:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, From, RSM) ->
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
node_hometree_odbc:get_items(NodeId, From, RSM).
|
node_hometree_odbc:get_items(Nidx, JID, AccessModel,
|
||||||
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_last_items(Nidx, JID, Count) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree_odbc:get_last_items(Nidx, JID, Count).
|
||||||
get_items(NodeId, JID, AccessModel,
|
|
||||||
PresenceSubscription, RosterGroup, SubId, none).
|
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_item(Nidx, ItemId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId, RSM) ->
|
node_hometree_odbc:get_item(Nidx, ItemId).
|
||||||
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
|
|
||||||
PresenceSubscription, RosterGroup, SubId, RSM).
|
|
||||||
|
|
||||||
get_last_items(NodeId, JID, Count) ->
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
node_hometree_odbc:get_last_items(NodeId, JID, Count).
|
node_hometree_odbc:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
set_item(Item) ->
|
||||||
node_hometree_odbc:get_item(NodeId, ItemId).
|
node_hometree_odbc:set_item(Item).
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
get_item_name(Host, Node, Id) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree_odbc: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
|
%%% 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
|
%% Check that the mod_caps module is enabled in that Jabber Host
|
||||||
%% If not, show a warning message in the ejabberd log file.
|
%% If not, show a warning message in the ejabberd log file.
|
||||||
complain_if_modcaps_disabled(ServerHost) ->
|
complain_if_modcaps_disabled(ServerHost) ->
|
||||||
Modules = ejabberd_config:get_option({modules,
|
case gen_mod:is_loaded(ServerHost, mod_caps) of
|
||||||
ServerHost},
|
false ->
|
||||||
fun(Ms) when is_list(Ms) -> Ms end),
|
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
|
||||||
ModCaps = [mod_caps_enabled
|
"of host ~p. This plugin requires mod_caps "
|
||||||
|| {mod_caps, _Opts} <- Modules],
|
"to be enabled, but it isn't.",
|
||||||
case ModCaps of
|
[ServerHost]);
|
||||||
[] ->
|
true -> ok
|
||||||
?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
|
|
||||||
end.
|
end.
|
||||||
|
@ -4,58 +4,45 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_private).
|
-module(node_private).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -64,121 +51,126 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, true},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, true},
|
||||||
{access_model, whitelist}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, never},
|
{access_model, whitelist},
|
||||||
{deliver_notifications, false},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, false}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
[<<"create-nodes">>,
|
||||||
<<"delete-items">>, <<"instant-nodes">>,
|
<<"delete-nodes">>,
|
||||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
<<"delete-items">>,
|
||||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
<<"instant-nodes">>,
|
||||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
<<"persistent-items">>,
|
||||||
<<"subscription-notifications">>].
|
<<"publish">>,
|
||||||
|
<<"purge-nodes">>,
|
||||||
|
<<"retract-items">>,
|
||||||
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
|
<<"subscribe">>,
|
||||||
|
<<"subscription-notifications">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_hometree:create_node_permission(Host, ServerHost,
|
|
||||||
Node, ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeId, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeId, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeId).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeId, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeId, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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).
|
||||||
|
@ -4,58 +4,45 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
||||||
%%% All Rights Reserved.''
|
%%% All Rights Reserved.''
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
%%% This software is copyright 2006-2015, ProcessOne.
|
||||||
%%%
|
%%%
|
||||||
%%%
|
|
||||||
%%% @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/]
|
%%% [http://www.process-one.net/]
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
%%% @end
|
%%% @end
|
||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(node_public).
|
-module(node_public).
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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,
|
-export([init/3, terminate/2, options/0, features/0,
|
||||||
create_node_permission/6, create_node/2, delete_node/1,
|
create_node_permission/6, create_node/2, delete_node/1,
|
||||||
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
purge_node/2, subscribe_node/8, unsubscribe_node/4,
|
||||||
publish_item/6, delete_item/4, remove_extra_items/3,
|
publish_item/6, delete_item/4, remove_extra_items/3,
|
||||||
get_entity_affiliations/2, get_node_affiliations/1,
|
get_entity_affiliations/2, get_node_affiliations/1,
|
||||||
get_affiliation/2, set_affiliation/3,
|
get_affiliation/2, set_affiliation/3,
|
||||||
get_entity_subscriptions/2, get_node_subscriptions/1,
|
get_entity_subscriptions/2, get_node_subscriptions/1,
|
||||||
get_subscriptions/2, set_subscriptions/4,
|
get_subscriptions/2, set_subscriptions/4,
|
||||||
get_pending_nodes/2, get_states/1, get_state/2,
|
get_pending_nodes/2, get_states/1, get_state/2,
|
||||||
set_state/1, get_items/6, get_items/2, get_item/7,
|
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,
|
get_item/2, set_item/1, get_item_name/3, node_to_path/1,
|
||||||
path_to_node/1]).
|
path_to_node/1]).
|
||||||
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
node_hometree:init(Host, ServerHost, Opts).
|
node_hometree:init(Host, ServerHost, Opts).
|
||||||
@ -64,123 +51,126 @@ terminate(Host, ServerHost) ->
|
|||||||
node_hometree:terminate(Host, ServerHost).
|
node_hometree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
options() ->
|
options() ->
|
||||||
[{deliver_payloads, true}, {notify_config, false},
|
[{deliver_payloads, true},
|
||||||
{notify_delete, false}, {notify_retract, true},
|
{notify_config, false},
|
||||||
{purge_offline, false}, {persist_items, true},
|
{notify_delete, false},
|
||||||
{max_items, ?MAXITEMS}, {subscribe, true},
|
{notify_retract, true},
|
||||||
{access_model, open}, {roster_groups_allowed, []},
|
{purge_offline, false},
|
||||||
{publish_model, publishers},
|
{persist_items, true},
|
||||||
{notification_type, headline},
|
{max_items, ?MAXITEMS},
|
||||||
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
{subscribe, true},
|
||||||
{send_last_published_item, never},
|
{access_model, open},
|
||||||
{deliver_notifications, true},
|
{roster_groups_allowed, []},
|
||||||
{presence_based_delivery, false}].
|
{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() ->
|
features() ->
|
||||||
[<<"create-nodes">>, <<"delete-nodes">>,
|
[<<"create-nodes">>,
|
||||||
<<"delete-items">>, <<"instant-nodes">>,
|
<<"delete-nodes">>,
|
||||||
<<"outcast-affiliation">>, <<"persistent-items">>,
|
<<"delete-items">>,
|
||||||
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
|
<<"instant-nodes">>,
|
||||||
<<"retrieve-affiliations">>, <<"retrieve-items">>,
|
<<"outcast-affiliation">>,
|
||||||
<<"retrieve-subscriptions">>, <<"subscribe">>,
|
<<"persistent-items">>,
|
||||||
<<"subscription-notifications">>].
|
<<"publish">>,
|
||||||
|
<<"purge-nodes">>,
|
||||||
|
<<"retract-items">>,
|
||||||
|
<<"retrieve-affiliations">>,
|
||||||
|
<<"retrieve-items">>,
|
||||||
|
<<"retrieve-subscriptions">>,
|
||||||
|
<<"subscribe">>,
|
||||||
|
<<"subscription-notifications">>].
|
||||||
|
|
||||||
create_node_permission(Host, ServerHost, Node,
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
ParentNode, Owner, Access) ->
|
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
|
||||||
node_hometree:create_node_permission(Host, ServerHost,
|
|
||||||
Node, ParentNode, Owner, Access).
|
|
||||||
|
|
||||||
create_node(NodeId, Owner) ->
|
create_node(Nidx, Owner) ->
|
||||||
node_hometree:create_node(NodeId, Owner).
|
node_hometree:create_node(Nidx, Owner).
|
||||||
|
|
||||||
delete_node(Removed) ->
|
delete_node(Removed) ->
|
||||||
node_hometree:delete_node(Removed).
|
node_hometree:delete_node(Removed).
|
||||||
|
|
||||||
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
|
subscribe_node(Nidx, Sender, Subscriber, AccessModel,
|
||||||
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
SendLast, PresenceSubscription, RosterGroup, Options) ->
|
||||||
node_hometree:subscribe_node(NodeId, Sender, Subscriber,
|
node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
|
||||||
AccessModel, SendLast, PresenceSubscription,
|
PresenceSubscription, RosterGroup, Options).
|
||||||
RosterGroup, Options).
|
|
||||||
|
|
||||||
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
|
||||||
node_hometree:unsubscribe_node(NodeId, Sender,
|
node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
|
||||||
Subscriber, SubID).
|
|
||||||
|
|
||||||
publish_item(NodeId, Publisher, Model, MaxItems, ItemId,
|
publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
Payload) ->
|
node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
node_hometree:publish_item(NodeId, Publisher, Model,
|
|
||||||
MaxItems, ItemId, Payload).
|
|
||||||
|
|
||||||
remove_extra_items(NodeId, MaxItems, ItemIds) ->
|
remove_extra_items(Nidx, MaxItems, ItemIds) ->
|
||||||
node_hometree:remove_extra_items(NodeId, MaxItems,
|
node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
|
||||||
ItemIds).
|
|
||||||
|
|
||||||
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
|
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
|
||||||
node_hometree:delete_item(NodeId, Publisher,
|
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
|
||||||
PublishModel, ItemId).
|
|
||||||
|
|
||||||
purge_node(NodeId, Owner) ->
|
purge_node(Nidx, Owner) ->
|
||||||
node_hometree:purge_node(NodeId, Owner).
|
node_hometree:purge_node(Nidx, Owner).
|
||||||
|
|
||||||
get_entity_affiliations(Host, Owner) ->
|
get_entity_affiliations(Host, Owner) ->
|
||||||
node_hometree:get_entity_affiliations(Host, Owner).
|
node_hometree:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
get_node_affiliations(NodeId) ->
|
get_node_affiliations(Nidx) ->
|
||||||
node_hometree:get_node_affiliations(NodeId).
|
node_hometree:get_node_affiliations(Nidx).
|
||||||
|
|
||||||
get_affiliation(NodeId, Owner) ->
|
get_affiliation(Nidx, Owner) ->
|
||||||
node_hometree:get_affiliation(NodeId, Owner).
|
node_hometree:get_affiliation(Nidx, Owner).
|
||||||
|
|
||||||
set_affiliation(NodeId, Owner, Affiliation) ->
|
set_affiliation(Nidx, Owner, Affiliation) ->
|
||||||
node_hometree:set_affiliation(NodeId, Owner,
|
node_hometree:set_affiliation(Nidx, Owner, Affiliation).
|
||||||
Affiliation).
|
|
||||||
|
|
||||||
get_entity_subscriptions(Host, Owner) ->
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
node_hometree:get_entity_subscriptions(Host, Owner).
|
node_hometree:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
get_node_subscriptions(NodeId) ->
|
get_node_subscriptions(Nidx) ->
|
||||||
node_hometree:get_node_subscriptions(NodeId).
|
node_hometree:get_node_subscriptions(Nidx).
|
||||||
|
|
||||||
get_subscriptions(NodeId, Owner) ->
|
get_subscriptions(Nidx, Owner) ->
|
||||||
node_hometree:get_subscriptions(NodeId, Owner).
|
node_hometree:get_subscriptions(Nidx, Owner).
|
||||||
|
|
||||||
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
|
set_subscriptions(Nidx, Owner, Subscription, SubId) ->
|
||||||
node_hometree:set_subscriptions(NodeId, Owner,
|
node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
|
||||||
Subscription, SubId).
|
|
||||||
|
|
||||||
get_pending_nodes(Host, Owner) ->
|
get_pending_nodes(Host, Owner) ->
|
||||||
node_hometree: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) ->
|
get_state(Nidx, JID) ->
|
||||||
node_hometree:get_state(NodeId, 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) ->
|
get_items(Nidx, From, RSM) ->
|
||||||
node_hometree:get_items(NodeId, From).
|
node_hometree:get_items(Nidx, From, RSM).
|
||||||
|
|
||||||
get_items(NodeId, JID, AccessModel,
|
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_items(Nidx, JID, AccessModel,
|
||||||
node_hometree:get_items(NodeId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId, RSM).
|
||||||
PresenceSubscription, RosterGroup, SubId).
|
|
||||||
|
|
||||||
get_item(NodeId, ItemId) ->
|
get_item(Nidx, ItemId) ->
|
||||||
node_hometree:get_item(NodeId, ItemId).
|
node_hometree:get_item(Nidx, ItemId).
|
||||||
|
|
||||||
get_item(NodeId, ItemId, JID, AccessModel,
|
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
PresenceSubscription, RosterGroup, SubId) ->
|
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
|
||||||
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
|
PresenceSubscription, RosterGroup, SubId).
|
||||||
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) ->
|
get_item_name(Host, Node, Id) ->
|
||||||
node_hometree: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).
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
%%% compliance with the License. You should have received a copy of the
|
%%% compliance with the License. You should have received a copy of the
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
%%% Erlang Public License along with this software. If not, it can be
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||||
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
%%% Software distributed under the License is distributed on an "AS IS"
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||||
%%% the License for the specific language governing rights and limitations
|
%%% the License for the specific language governing rights and limitations
|
||||||
%%% under the License.
|
%%% under the License.
|
||||||
|
%%%
|
||||||
%%%
|
%%%
|
||||||
%%% @author Brian Cully <bjc@kublai.com>
|
%%% @author Brian Cully <bjc@kublai.com>
|
||||||
%%% @version {@vsn}, {@date} {@time}
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
@ -16,219 +18,141 @@
|
|||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(nodetree_dag).
|
-module(nodetree_dag).
|
||||||
|
-behaviour(gen_pubsub_nodetree).
|
||||||
-author('bjc@kublai.com').
|
-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_lib("stdlib/include/qlc.hrl").
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
|
||||||
-include("logger.hrl").
|
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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_NODETYPE, leaf).
|
||||||
|
|
||||||
-define(DEFAULT_PARENTS, []).
|
-define(DEFAULT_PARENTS, []).
|
||||||
|
|
||||||
-define(DEFAULT_CHILDREN, []).
|
-define(DEFAULT_CHILDREN, []).
|
||||||
|
|
||||||
-compile(export_all).
|
|
||||||
|
|
||||||
%%====================================================================
|
|
||||||
%% API
|
|
||||||
%%====================================================================
|
|
||||||
init(Host, ServerHost, Opts) ->
|
init(Host, ServerHost, Opts) ->
|
||||||
nodetree_tree:init(Host, ServerHost, Opts).
|
nodetree_tree:init(Host, ServerHost, Opts).
|
||||||
|
|
||||||
terminate(Host, ServerHost) ->
|
terminate(Host, ServerHost) ->
|
||||||
nodetree_tree:terminate(Host, ServerHost).
|
nodetree_tree:terminate(Host, ServerHost).
|
||||||
|
|
||||||
-spec(create_node/6 ::
|
set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} = Node) ->
|
||||||
(
|
|
||||||
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) ->
|
|
||||||
Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
|
Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
|
||||||
case validate_parentage(Key, Owners, Parents) of
|
case validate_parentage(Key, Owners, Parents) of
|
||||||
true ->
|
true -> mnesia:write(Node#pubsub_node{parents = Parents});
|
||||||
mnesia:write(Node#pubsub_node{parents = Parents});
|
Other -> Other
|
||||||
Other -> Other
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(delete_node/2 ::
|
create_node(Key, Node, Type, Owner, Options, Parents) ->
|
||||||
(
|
OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||||
Key :: mod_pubsub:hostPubsub(),
|
case find_node(Key, Node) of
|
||||||
NodeID :: mod_pubsub:nodeId())
|
false ->
|
||||||
-> [mod_pubsub:pubsubNode(),...]
|
Nidx = pubsub_index:new(node),
|
||||||
%%%
|
N = #pubsub_node{nodeid = oid(Key, Node), id = Nidx,
|
||||||
| {error, xmlel()}
|
type = Type, parents = Parents, owners = [OwnerJID],
|
||||||
).
|
options = Options},
|
||||||
delete_node(Key, NodeID) ->
|
case set_node(N) of
|
||||||
case find_node(Key, NodeID) of
|
ok -> {ok, Nidx};
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
Other -> Other
|
||||||
Node ->
|
end;
|
||||||
lists:foreach(fun (#pubsub_node{options = Opts} =
|
_ ->
|
||||||
Child) ->
|
{error, ?ERR_CONFLICT}
|
||||||
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]
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
options() -> nodetree_tree:options().
|
delete_node(Key, Node) ->
|
||||||
|
case find_node(Key, Node) of
|
||||||
get_node(Host, NodeID, _From) -> get_node(Host, NodeID).
|
false ->
|
||||||
|
{error, ?ERR_ITEM_NOT_FOUND};
|
||||||
-spec(get_node/2 ::
|
Record ->
|
||||||
(
|
lists:foreach(fun (#pubsub_node{options = Opts} = Child) ->
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
NewOpts = remove_config_parent(Node, Opts),
|
||||||
NodeID :: mod_pubsub:nodeId())
|
Parents = find_opt(collection, ?DEFAULT_PARENTS, NewOpts),
|
||||||
-> mod_pubsub:pubsubNode()
|
ok = mnesia:write(pubsub_node,
|
||||||
%%%
|
Child#pubsub_node{parents = Parents,
|
||||||
| {error, xmlel}
|
options = NewOpts},
|
||||||
).
|
write)
|
||||||
get_node(Host, NodeID) ->
|
end,
|
||||||
case find_node(Host, NodeID) of
|
get_subnodes(Key, Node)),
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
pubsub_index:free(node, Record#pubsub_node.id),
|
||||||
Node -> Node
|
mnesia:delete_object(pubsub_node, Record, write),
|
||||||
|
[Record]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(get_node/1 ::
|
options() ->
|
||||||
(
|
nodetree_tree:options().
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> mod_pubsub:pubsubNode()
|
get_node(Host, Node, _From) ->
|
||||||
| {error, xmlel()}
|
get_node(Host, Node).
|
||||||
).
|
|
||||||
get_node(NodeId) -> nodetree_tree:get_node(NodeId).
|
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) ->
|
get_nodes(Key, From) ->
|
||||||
nodetree_tree:get_nodes(Key, From).
|
nodetree_tree:get_nodes(Key, From).
|
||||||
|
|
||||||
-spec(get_nodes/1 ::
|
get_nodes(Key) ->
|
||||||
(
|
nodetree_tree:get_nodes(Key).
|
||||||
Host::mod_pubsub:host())
|
|
||||||
-> [mod_pubsub:pubsubNode()]
|
|
||||||
).
|
|
||||||
get_nodes(Key) -> nodetree_tree:get_nodes(Key).
|
|
||||||
|
|
||||||
-spec(get_parentnodes/3 ::
|
get_parentnodes(Host, Node, _From) ->
|
||||||
(
|
case find_node(Host, Node) of
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
false ->
|
||||||
NodeID :: mod_pubsub:nodeId(),
|
{error, ?ERR_ITEM_NOT_FOUND};
|
||||||
_From :: _)
|
#pubsub_node{parents = Parents} ->
|
||||||
-> [mod_pubsub:pubsubNode()]
|
Q = qlc:q([N
|
||||||
%%%
|
|| #pubsub_node{nodeid = {NHost, NNode}} = N
|
||||||
| {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
|
|
||||||
<- mnesia:table(pubsub_node),
|
<- mnesia:table(pubsub_node),
|
||||||
Parent <- Parents, Host == NHost, Parent == NNode]),
|
Parent <- Parents, Host == NHost, Parent == NNode]),
|
||||||
qlc:e(Q)
|
qlc:e(Q)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_parentnodes_tree(Host, NodeID, _From) ->
|
get_parentnodes_tree(Host, Node, _From) ->
|
||||||
Pred = fun (NID, #pubsub_node{nodeid = {_, NNodeID}}) ->
|
Pred = fun (NID, #pubsub_node{nodeid = {_, NNode}}) ->
|
||||||
NID == NNodeID
|
NID == NNode
|
||||||
end,
|
end,
|
||||||
Tr = fun (#pubsub_node{parents = Parents}) -> Parents
|
Tr = fun (#pubsub_node{parents = Parents}) -> Parents
|
||||||
end,
|
end,
|
||||||
traversal_helper(Pred, Tr, Host, [NodeID]).
|
traversal_helper(Pred, Tr, Host, [Node]).
|
||||||
|
|
||||||
get_subnodes(Host, NodeID, _From) ->
|
get_subnodes(Host, Node, _From) ->
|
||||||
get_subnodes(Host, NodeID).
|
get_subnodes(Host, Node).
|
||||||
|
|
||||||
-spec(get_subnodes/2 ::
|
|
||||||
(
|
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
|
||||||
NodeId :: mod_pubsub:nodeId())
|
|
||||||
-> [mod_pubsub:pubsubNode()]
|
|
||||||
).
|
|
||||||
get_subnodes(Host, <<>>) ->
|
get_subnodes(Host, <<>>) ->
|
||||||
get_subnodes_helper(Host, <<>>);
|
get_subnodes_helper(Host, <<>>);
|
||||||
get_subnodes(Host, NodeID) ->
|
get_subnodes(Host, Node) ->
|
||||||
case find_node(Host, NodeID) of
|
case find_node(Host, Node) of
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
||||||
_ -> get_subnodes_helper(Host, NodeID)
|
_ -> get_subnodes_helper(Host, Node)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(get_subnodes_helper/2 ::
|
get_subnodes_helper(Host, Node) ->
|
||||||
(
|
Q = qlc:q([N
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
|| #pubsub_node{nodeid = {NHost, _},
|
||||||
NodeID :: mod_pubsub:nodeId())
|
parents = Parents} =
|
||||||
-> [mod_pubsub:pubsubNode()]
|
N
|
||||||
).
|
<- mnesia:table(pubsub_node),
|
||||||
get_subnodes_helper(Host, NodeID) ->
|
Host == NHost, lists:member(Node, Parents)]),
|
||||||
Q = qlc:q([Node
|
|
||||||
|| #pubsub_node{nodeid = {NHost, _},
|
|
||||||
parents = Parents} =
|
|
||||||
Node
|
|
||||||
<- mnesia:table(pubsub_node),
|
|
||||||
Host == NHost, lists:member(NodeID, Parents)]),
|
|
||||||
qlc:e(Q).
|
qlc:e(Q).
|
||||||
|
|
||||||
get_subnodes_tree(Host, NodeID, From) ->
|
get_subnodes_tree(Host, Node, From) ->
|
||||||
Pred = fun (NID, #pubsub_node{parents = Parents}) ->
|
Pred = fun (NID, #pubsub_node{parents = Parents}) ->
|
||||||
lists:member(NID, Parents)
|
lists:member(NID, Parents)
|
||||||
end,
|
end,
|
||||||
Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end,
|
Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end,
|
||||||
traversal_helper(Pred, Tr, 1, Host, [NodeID],
|
traversal_helper(Pred, Tr, 1, Host, [Node],
|
||||||
[{0, [get_node(Host, NodeID, From)]}]).
|
[{0, [get_node(Host, Node, From)]}]).
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
@ -236,17 +160,17 @@ get_subnodes_tree(Host, NodeID, From) ->
|
|||||||
oid(Key, Name) -> {Key, Name}.
|
oid(Key, Name) -> {Key, Name}.
|
||||||
|
|
||||||
%% Key = jlib:jid() | host()
|
%% Key = jlib:jid() | host()
|
||||||
%% NodeID = string()
|
%% Node = string()
|
||||||
-spec(find_node/2 ::
|
-spec(find_node/2 ::
|
||||||
(
|
(
|
||||||
Key :: mod_pubsub:hostPubsub(),
|
Key :: mod_pubsub:hostPubsub(),
|
||||||
NodeID :: mod_pubsub:nodeId())
|
Node :: mod_pubsub:nodeId())
|
||||||
-> mod_pubsub:pubsubNode() | false
|
-> mod_pubsub:pubsubNode() | false
|
||||||
).
|
).
|
||||||
find_node(Key, NodeID) ->
|
find_node(Key, Node) ->
|
||||||
case mnesia:read(pubsub_node, oid(Key, NodeID), read) of
|
case mnesia:read(pubsub_node, oid(Key, Node), read) of
|
||||||
[] -> false;
|
[] -> false;
|
||||||
[Node] -> Node
|
[Node] -> Node
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Key = jlib:jid() | host()
|
%% Key = jlib:jid() | host()
|
||||||
@ -254,77 +178,67 @@ find_node(Key, NodeID) ->
|
|||||||
%% Options = [{Key = atom(), Value = term()}]
|
%% Options = [{Key = atom(), Value = term()}]
|
||||||
find_opt(Key, Default, Options) ->
|
find_opt(Key, Default, Options) ->
|
||||||
case lists:keysearch(Key, 1, Options) of
|
case lists:keysearch(Key, 1, Options) of
|
||||||
{value, {Key, Val}} -> Val;
|
{value, {Key, Val}} -> Val;
|
||||||
_ -> Default
|
_ -> Default
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(traversal_helper/4 ::
|
-spec(traversal_helper/4 ::
|
||||||
(
|
(
|
||||||
Pred :: fun(),
|
Pred :: fun(),
|
||||||
Tr :: fun(),
|
Tr :: fun(),
|
||||||
Host :: mod_pubsub:hostPubsub(),
|
Host :: mod_pubsub:hostPubsub(),
|
||||||
NodeId :: [mod_pubsub:pubsubNode(),...])
|
Nodes :: [mod_pubsub:nodeId(),...])
|
||||||
-> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}]
|
-> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}]
|
||||||
).
|
).
|
||||||
|
traversal_helper(Pred, Tr, Host, Nodes) ->
|
||||||
traversal_helper(Pred, Tr, Host, NodeIDs) ->
|
traversal_helper(Pred, Tr, 0, Host, Nodes, []).
|
||||||
traversal_helper(Pred, Tr, 0, Host, NodeIDs, []).
|
|
||||||
|
|
||||||
traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) ->
|
traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) ->
|
||||||
Acc;
|
Acc;
|
||||||
traversal_helper(Pred, Tr, Depth, Host, NodeIDs, Acc) ->
|
traversal_helper(Pred, Tr, Depth, Host, Nodes, Acc) ->
|
||||||
Q = qlc:q([Node
|
Q = qlc:q([N
|
||||||
|| #pubsub_node{nodeid = {NHost, _}} = Node
|
|| #pubsub_node{nodeid = {NHost, _}} = N
|
||||||
<- mnesia:table(pubsub_node),
|
<- mnesia:table(pubsub_node),
|
||||||
NodeID <- NodeIDs, Host == NHost, Pred(NodeID, Node)]),
|
Node <- Nodes, Host == NHost, Pred(Node, N)]),
|
||||||
Nodes = qlc:e(Q),
|
Nodes = qlc:e(Q),
|
||||||
IDs = lists:flatmap(Tr, Nodes),
|
IDs = lists:flatmap(Tr, Nodes),
|
||||||
traversal_helper(Pred, Tr, Depth + 1, Host, IDs,
|
traversal_helper(Pred, Tr, Depth + 1, Host, IDs, [{Depth, Nodes} | Acc]).
|
||||||
[{Depth, Nodes} | Acc]).
|
|
||||||
|
|
||||||
remove_config_parent(NodeID, Options) ->
|
remove_config_parent(Node, Options) ->
|
||||||
remove_config_parent(NodeID, Options, []).
|
remove_config_parent(Node, Options, []).
|
||||||
|
|
||||||
remove_config_parent(_NodeID, [], Acc) ->
|
remove_config_parent(_Node, [], Acc) ->
|
||||||
lists:reverse(Acc);
|
lists:reverse(Acc);
|
||||||
remove_config_parent(NodeID, [{collection, Parents} | T], Acc) ->
|
remove_config_parent(Node, [{collection, Parents} | T], Acc) ->
|
||||||
remove_config_parent(NodeID, T,
|
remove_config_parent(Node, T, [{collection, lists:delete(Node, Parents)} | Acc]);
|
||||||
[{collection, lists:delete(NodeID, Parents)} | Acc]);
|
remove_config_parent(Node, [H | T], Acc) ->
|
||||||
remove_config_parent(NodeID, [H | T], Acc) ->
|
remove_config_parent(Node, T, [H | Acc]).
|
||||||
remove_config_parent(NodeID, T, [H | Acc]).
|
|
||||||
|
|
||||||
-spec(validate_parentage/3 ::
|
-spec(validate_parentage/3 ::
|
||||||
(
|
(
|
||||||
Key :: mod_pubsub:hostPubsub(),
|
Key :: mod_pubsub:hostPubsub(),
|
||||||
Owners :: [ljid(),...],
|
Owners :: [ljid(),...],
|
||||||
Parent_NodeIds :: [mod_pubsub:nodeId()])
|
Parent_Nodes :: [mod_pubsub:nodeId()])
|
||||||
-> true
|
-> true
|
||||||
%%%
|
%%%
|
||||||
| {error, xmlel()}
|
| {error, xmlel()}
|
||||||
).
|
).
|
||||||
validate_parentage(_Key, _Owners, []) -> true;
|
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, [<<>> | T]) ->
|
validate_parentage(Key, Owners, [<<>> | T]) ->
|
||||||
validate_parentage(Key, Owners, T);
|
validate_parentage(Key, Owners, T);
|
||||||
validate_parentage(Key, Owners, [ParentID | T]) ->
|
validate_parentage(Key, Owners, [ParentID | T]) ->
|
||||||
case find_node(Key, ParentID) of
|
case find_node(Key, ParentID) of
|
||||||
false -> {error, ?ERR_ITEM_NOT_FOUND};
|
false ->
|
||||||
#pubsub_node{owners = POwners, options = POptions} ->
|
{error, ?ERR_ITEM_NOT_FOUND};
|
||||||
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
|
#pubsub_node{owners = POwners, options = POptions} ->
|
||||||
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
|
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
|
||||||
case {MutualOwners, NodeType} of
|
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
|
||||||
{[], _} -> {error, ?ERR_FORBIDDEN};
|
case {MutualOwners, NodeType} of
|
||||||
{_, collection} -> validate_parentage(Key, Owners, T);
|
{[], _} -> {error, ?ERR_FORBIDDEN};
|
||||||
{_, _} -> {error, ?ERR_NOT_ALLOWED}
|
{_, collection} -> validate_parentage(Key, Owners, T);
|
||||||
end
|
{_, _} -> {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, <<>>)
|
|
||||||
end.
|
end.
|
||||||
|
@ -36,287 +36,163 @@
|
|||||||
%%% improvements.</p>
|
%%% improvements.</p>
|
||||||
|
|
||||||
-module(nodetree_tree).
|
-module(nodetree_tree).
|
||||||
|
-behaviour(gen_pubsub_nodetree).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include_lib("stdlib/include/qlc.hrl").
|
-include_lib("stdlib/include/qlc.hrl").
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_nodetree).
|
|
||||||
|
|
||||||
-export([init/3, terminate/2, options/0, set_node/1,
|
-export([init/3, terminate/2, options/0, set_node/1,
|
||||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||||
delete_node/2]).
|
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) ->
|
init(_Host, _ServerHost, _Options) ->
|
||||||
mnesia:create_table(pubsub_node,
|
mnesia:create_table(pubsub_node,
|
||||||
[{disc_copies, [node()]},
|
[{disc_copies, [node()]},
|
||||||
{attributes, record_info(fields, pubsub_node)}]),
|
{attributes, record_info(fields, pubsub_node)}]),
|
||||||
mnesia:add_table_index(pubsub_node, id),
|
mnesia:add_table_index(pubsub_node, id),
|
||||||
NodesFields = record_info(fields, pubsub_node),
|
NodesFields = record_info(fields, pubsub_node),
|
||||||
case mnesia:table_info(pubsub_node, attributes) of
|
case mnesia:table_info(pubsub_node, attributes) of
|
||||||
NodesFields -> ok;
|
NodesFields -> ok;
|
||||||
_ -> ok
|
_ -> ok
|
||||||
end,
|
end,
|
||||||
%% mnesia:transform_table(pubsub_state, ignore, StatesFields)
|
%% mnesia:transform_table(pubsub_state, ignore, StatesFields)
|
||||||
ok.
|
ok.
|
||||||
%% @spec (Host, ServerHost) -> ok
|
|
||||||
%% Host = string()
|
|
||||||
%% ServerHost = string()
|
|
||||||
|
|
||||||
%% @spec () -> Options
|
terminate(_Host, _ServerHost) ->
|
||||||
%% Options = [mod_pubsub:nodeOption()]
|
ok.
|
||||||
%% @doc Returns the default pubsub node tree options.
|
|
||||||
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) ->
|
set_node(Node) when is_record(Node, pubsub_node) ->
|
||||||
mnesia:write(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}
|
get_node(Host, Node) ->
|
||||||
%% Host = mod_pubsub:host()
|
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||||
%% NodeId = mod_pubsub:nodeId()
|
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||||
%% Node = mod_pubsub:pubsubNode()
|
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||||
%% 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
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(get_node/1 ::
|
get_node(Nidx) ->
|
||||||
(
|
case catch mnesia:index_read(pubsub_node, Nidx, #pubsub_node.id) of
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||||
-> mod_pubsub:pubsubNode()
|
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
||||||
| {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
|
|
||||||
end.
|
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) ->
|
get_nodes(Host) ->
|
||||||
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
|
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
|
||||||
|
|
||||||
%% @spec (Host, Node, From) -> []
|
get_parentnodes(_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) -> [].
|
|
||||||
|
|
||||||
%% @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
|
%% @doc <p>Default node tree does not handle parents, return a list
|
||||||
%% containing just this node.</p>
|
%% containing just this node.</p>
|
||||||
-spec(get_parentnodes_tree/3 ::
|
get_parentnodes_tree(Host, Node, _From) ->
|
||||||
(
|
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||||
Host :: mod_pubsub:host(),
|
[Record] when is_record(Record, pubsub_node) -> [{0, [Record]}];
|
||||||
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 -> []
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, NodeId, From) -> Nodes
|
get_subnodes(Host, Node, _From) ->
|
||||||
%% Host = mod_pubsub:host()
|
get_subnodes(Host, Node).
|
||||||
%% NodeId = mod_pubsub:nodeId()
|
|
||||||
%% From = mod_pubsub:jid()
|
|
||||||
%% Nodes = [mod_pubsub:pubsubNode()]
|
|
||||||
get_subnodes(Host, NodeId, _From) ->
|
|
||||||
get_subnodes(Host, NodeId).
|
|
||||||
|
|
||||||
-spec(get_subnodes/2 ::
|
|
||||||
(
|
|
||||||
Host :: mod_pubsub:host(),
|
|
||||||
NodeId :: mod_pubsub:nodeId())
|
|
||||||
-> [mod_pubsub:pubsubNode()]
|
|
||||||
).
|
|
||||||
get_subnodes(Host, <<>>) ->
|
get_subnodes(Host, <<>>) ->
|
||||||
Q = qlc:q([N
|
Q = qlc:q([N
|
||||||
|| #pubsub_node{nodeid = {NHost, _},
|
|| #pubsub_node{nodeid = {NHost, _},
|
||||||
parents = Parents} =
|
parents = Parents} =
|
||||||
N
|
N
|
||||||
<- mnesia:table(pubsub_node),
|
<- mnesia:table(pubsub_node),
|
||||||
Host == NHost, Parents == []]),
|
Host == NHost, Parents == []]),
|
||||||
qlc:e(Q);
|
qlc:e(Q);
|
||||||
get_subnodes(Host, Node) ->
|
get_subnodes(Host, Node) ->
|
||||||
Q = qlc:q([N
|
Q = qlc:q([N
|
||||||
|| #pubsub_node{nodeid = {NHost, _},
|
|| #pubsub_node{nodeid = {NHost, _},
|
||||||
parents = Parents} =
|
parents = Parents} =
|
||||||
N
|
N
|
||||||
<- mnesia:table(pubsub_node),
|
<- mnesia:table(pubsub_node),
|
||||||
Host == NHost, lists:member(Node, Parents)]),
|
Host == NHost, lists:member(Node, Parents)]),
|
||||||
qlc:e(Q).
|
qlc:e(Q).
|
||||||
|
|
||||||
get_subnodes_tree(Host, Node, _From) ->
|
get_subnodes_tree(Host, Node, _From) ->
|
||||||
get_subnodes_tree(Host, Node).
|
get_subnodes_tree(Host, Node).
|
||||||
|
|
||||||
%% @spec (Host, NodeId) -> Nodes
|
get_subnodes_tree(Host, Node) ->
|
||||||
%% Host = mod_pubsub:host()
|
case get_node(Host, Node) of
|
||||||
%% NodeId = mod_pubsub:nodeId()
|
{error, _} ->
|
||||||
%% Nodes = [] | [mod_pubsub:pubsubNode()]
|
[];
|
||||||
-spec(get_subnodes_tree/2 ::
|
Rec ->
|
||||||
(
|
BasePlugin = jlib:binary_to_atom(<<"node_",
|
||||||
Host :: mod_pubsub:host(),
|
(Rec#pubsub_node.type)/binary>>),
|
||||||
NodeId :: mod_pubsub:nodeId())
|
BasePath = BasePlugin:node_to_path(Node),
|
||||||
-> [mod_pubsub:pubsubNode()]
|
mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R, Acc) ->
|
||||||
).
|
Plugin = jlib:binary_to_atom(<<"node_",
|
||||||
get_subnodes_tree(Host, NodeId) ->
|
(R#pubsub_node.type)/binary>>),
|
||||||
case get_node(Host, NodeId) of
|
Path = Plugin:node_to_path(N),
|
||||||
{error, _} -> [];
|
case lists:prefix(BasePath, Path) and (H == Host) of
|
||||||
Rec ->
|
true -> [R | Acc];
|
||||||
BasePlugin = jlib:binary_to_atom(<<"node_",
|
false -> Acc
|
||||||
(Rec#pubsub_node.type)/binary>>),
|
end
|
||||||
BasePath = BasePlugin:node_to_path(NodeId),
|
end,
|
||||||
mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R,
|
[], pubsub_node)
|
||||||
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.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, NodeId, Type, Owner, Options, Parents) ->
|
create_node(Host, Node, 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) ->
|
|
||||||
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||||
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of
|
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||||
[] ->
|
[] ->
|
||||||
ParentExists = case Host of
|
ParentExists = case Host of
|
||||||
{_U, _S, _R} ->
|
{_U, _S, _R} ->
|
||||||
%% This is special case for PEP handling
|
%% This is special case for PEP handling
|
||||||
%% PEP does not uses hierarchy
|
%% PEP does not uses hierarchy
|
||||||
true;
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
case Parents of
|
case Parents of
|
||||||
[] -> true;
|
[] ->
|
||||||
[Parent | _] ->
|
true;
|
||||||
case catch mnesia:read({pubsub_node,
|
[Parent | _] ->
|
||||||
{Host, Parent}})
|
case catch mnesia:read({pubsub_node, {Host, Parent}}) of
|
||||||
of
|
[#pubsub_node{owners = [{[], Host, []}]}] ->
|
||||||
[#pubsub_node{owners =
|
true;
|
||||||
[{[], Host, []}]}] ->
|
[#pubsub_node{owners = Owners}] ->
|
||||||
true;
|
lists:member(BJID, Owners);
|
||||||
[#pubsub_node{owners = Owners}] ->
|
_ ->
|
||||||
lists:member(BJID, Owners);
|
false
|
||||||
_ -> false
|
end;
|
||||||
end;
|
_ ->
|
||||||
_ -> false
|
false
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
case ParentExists of
|
case ParentExists of
|
||||||
true ->
|
true ->
|
||||||
NodeIdx = pubsub_index:new(node),
|
Nidx = pubsub_index:new(node),
|
||||||
mnesia:write(#pubsub_node{nodeid = {Host, NodeId},
|
mnesia:write(#pubsub_node{nodeid = {Host, Node},
|
||||||
id = NodeIdx, parents = Parents,
|
id = Nidx, parents = Parents,
|
||||||
type = Type, owners = [BJID],
|
type = Type, owners = [BJID],
|
||||||
options = Options}),
|
options = Options}),
|
||||||
{ok, NodeIdx};
|
{ok, Nidx};
|
||||||
false -> {error, ?ERR_FORBIDDEN}
|
false ->
|
||||||
end;
|
{error, ?ERR_FORBIDDEN}
|
||||||
_ -> {error, ?ERR_CONFLICT}
|
end;
|
||||||
|
_ ->
|
||||||
|
{error, ?ERR_CONFLICT}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, NodeId) -> Removed
|
delete_node(Host, Node) ->
|
||||||
%% Host = mod_pubsub:host()
|
Removed = get_subnodes_tree(Host, Node),
|
||||||
%% NodeId = mod_pubsub:nodeId()
|
lists:foreach(fun (#pubsub_node{nodeid = {_, SubNode}, id = SubNidx}) ->
|
||||||
%% Removed = [mod_pubsub:pubsubNode()]
|
pubsub_index:free(node, SubNidx),
|
||||||
-spec(delete_node/2 ::
|
mnesia:delete({pubsub_node, {Host, SubNode}})
|
||||||
(
|
end,
|
||||||
Host :: mod_pubsub:host(),
|
Removed),
|
||||||
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),
|
|
||||||
Removed.
|
Removed.
|
||||||
|
@ -36,437 +36,280 @@
|
|||||||
%%% improvements.</p>
|
%%% improvements.</p>
|
||||||
|
|
||||||
-module(nodetree_tree_odbc).
|
-module(nodetree_tree_odbc).
|
||||||
|
-behaviour(gen_pubsub_nodetree).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.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,
|
-export([init/3, terminate/2, options/0, set_node/1,
|
||||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||||
delete_node/2]).
|
delete_node/2]).
|
||||||
|
|
||||||
-export([raw_to_node/2]).
|
-export([raw_to_node/2]).
|
||||||
|
|
||||||
%% ================
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
%% API definition
|
ok.
|
||||||
%% ================
|
|
||||||
|
|
||||||
%% @spec (Host, ServerHost, Opts) -> any()
|
terminate(_Host, _ServerHost) ->
|
||||||
%% Host = mod_pubsub:host()
|
ok.
|
||||||
%% 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.
|
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) ->
|
get_node(Host, Node) ->
|
||||||
H = (?PUBSUB):escape(Host),
|
H = node_hometree_odbc:encode_host(Host),
|
||||||
N = (?PUBSUB):escape(Node),
|
N = ejabberd_odbc:escape(Node),
|
||||||
case catch
|
case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||||
"pubsub_node where host='">>,
|
"pubsub_node where host='">>,
|
||||||
H, <<"' and node='">>, N, <<"';">>])
|
H, <<"' and node='">>, N, <<"';">>])
|
||||||
of
|
of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [RItem]} ->
|
||||||
[RItem]} ->
|
raw_to_node(Host, RItem);
|
||||||
raw_to_node(Host, RItem);
|
{'EXIT', _Reason} ->
|
||||||
{'EXIT', _Reason} ->
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
_ ->
|
||||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
{error, ?ERR_ITEM_NOT_FOUND}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(get_node/1 ::
|
get_node(Nidx) ->
|
||||||
(
|
|
||||||
NodeIdx::mod_pubsub:nodeIdx())
|
|
||||||
-> mod_pubsub:pubsubNode()
|
|
||||||
| {error, _}
|
|
||||||
).
|
|
||||||
get_node(NodeIdx) ->
|
|
||||||
case catch
|
case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from "
|
ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from "
|
||||||
"pubsub_node where nodeid='">>,
|
"pubsub_node where nodeid='">>,
|
||||||
NodeIdx, <<"';">>])
|
Nidx, <<"';">>])
|
||||||
of
|
of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"host">>, <<"node">>, <<"parent">>, <<"type">>],
|
[<<"host">>, <<"node">>, <<"parent">>, <<"type">>], [[Host, Node, Parent, Type]]} ->
|
||||||
[[Host, Node, Parent, Type]]} ->
|
raw_to_node(Host, [Node, Parent, Type, Nidx]);
|
||||||
raw_to_node(Host, [Node, Parent, Type, NodeIdx]);
|
{'EXIT', _Reason} ->
|
||||||
{'EXIT', _Reason} ->
|
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
_ ->
|
||||||
_ -> {error, ?ERR_ITEM_NOT_FOUND}
|
{error, ?ERR_ITEM_NOT_FOUND}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, From) -> [pubsubNode()] | {error, Reason}
|
get_nodes(Host, _From) ->
|
||||||
%% Host = mod_pubsub:host() | mod_pubsub:jid()
|
get_nodes(Host).
|
||||||
get_nodes(Host, _From) -> get_nodes(Host).
|
|
||||||
|
|
||||||
-spec(get_nodes/1 ::
|
|
||||||
(
|
|
||||||
Host::mod_pubsub:host())
|
|
||||||
-> [mod_pubsub:pubsubNode()]
|
|
||||||
).
|
|
||||||
get_nodes(Host) ->
|
get_nodes(Host) ->
|
||||||
H = (?PUBSUB):escape(Host),
|
H = node_hometree_odbc:encode_host(Host),
|
||||||
case catch
|
case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||||
"pubsub_node where host='">>,
|
"pubsub_node where host='">>, H, <<"';">>])
|
||||||
H, <<"';">>])
|
of
|
||||||
of
|
{selected,
|
||||||
{selected,
|
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
RItems} ->
|
_ ->
|
||||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
[]
|
||||||
RItems);
|
|
||||||
_ -> []
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason}
|
get_parentnodes(_Host, _Node, _From) ->
|
||||||
%% 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()
|
|
||||||
%% @doc <p>Default node tree does not handle parents, return a list
|
%% @doc <p>Default node tree does not handle parents, return a list
|
||||||
%% containing just this node.</p>
|
%% 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) ->
|
get_parentnodes_tree(Host, Node, From) ->
|
||||||
case get_node(Host, Node, From) of
|
case get_node(Host, Node, From) of
|
||||||
N when is_record(N, pubsub_node) -> [{0, [N]}];
|
{error, _} -> [];
|
||||||
_Error -> []
|
Record -> [{0, [Record]}]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subnodes(Host, Node, _From) ->
|
get_subnodes(Host, Node, _From) ->
|
||||||
get_subnodes(Host, Node).
|
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) ->
|
get_subnodes(Host, Node) ->
|
||||||
H = (?PUBSUB):escape(Host),
|
H = node_hometree_odbc:encode_host(Host),
|
||||||
N = (?PUBSUB):escape(Node),
|
N = ejabberd_odbc:escape(Node),
|
||||||
case catch
|
case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||||
"pubsub_node where host='">>,
|
"pubsub_node where host='">>,
|
||||||
H, <<"' and parent='">>, N, <<"';">>])
|
H, <<"' and parent='">>, N, <<"';">>])
|
||||||
of
|
of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||||
RItems} ->
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
_ ->
|
||||||
RItems);
|
[]
|
||||||
_ -> []
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subnodes_tree(Host, Node, _From) ->
|
get_subnodes_tree(Host, Node, _From) ->
|
||||||
get_subnodes_tree(Host, Node).
|
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) ->
|
get_subnodes_tree(Host, Node) ->
|
||||||
H = (?PUBSUB):escape(Host),
|
H = node_hometree_odbc:encode_host(Host),
|
||||||
N = (?PUBSUB):escape(Node),
|
N = ejabberd_odbc:escape(Node),
|
||||||
case catch
|
case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
|
||||||
"pubsub_node where host='">>,
|
"pubsub_node where host='">>,
|
||||||
H, <<"' and node like '">>, N, <<"%';">>])
|
H, <<"' and node like '">>, N, <<"%';">>])
|
||||||
of
|
of
|
||||||
{selected,
|
{selected,
|
||||||
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>],
|
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
|
||||||
RItems} ->
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
lists:map(fun (Item) -> raw_to_node(Host, Item) end,
|
_ ->
|
||||||
RItems);
|
[]
|
||||||
_ -> []
|
|
||||||
end.
|
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) ->
|
create_node(Host, Node, Type, Owner, Options, Parents) ->
|
||||||
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||||
case nodeid(Host, Node) of
|
case nodeidx(Host, Node) of
|
||||||
{error, ?ERR_ITEM_NOT_FOUND} ->
|
{error, ?ERR_ITEM_NOT_FOUND} ->
|
||||||
ParentExists = case Host of
|
ParentExists = case Host of
|
||||||
{_U, _S, _R} ->
|
{_U, _S, _R} ->
|
||||||
%% This is special case for PEP handling
|
%% This is special case for PEP handling
|
||||||
%% PEP does not uses hierarchy
|
%% PEP does not uses hierarchy
|
||||||
true;
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
case Parents of
|
case Parents of
|
||||||
[] -> true;
|
[] ->
|
||||||
[Parent | _] ->
|
true;
|
||||||
case nodeid(Host, Parent) of
|
[Parent | _] ->
|
||||||
{result, PNodeId} ->
|
case nodeidx(Host, Parent) of
|
||||||
case nodeowners(PNodeId) of
|
{result, PNode} ->
|
||||||
[{<<>>, Host, <<>>}] -> true;
|
case nodeowners(PNode) of
|
||||||
Owners ->
|
[{<<>>, Host, <<>>}] -> true;
|
||||||
lists:member(BJID, Owners)
|
Owners -> lists:member(BJID, Owners)
|
||||||
end;
|
end;
|
||||||
_ -> false
|
_ ->
|
||||||
end;
|
false
|
||||||
_ -> false
|
end;
|
||||||
end
|
_ ->
|
||||||
end,
|
false
|
||||||
case ParentExists of
|
end
|
||||||
true ->
|
end,
|
||||||
case set_node(#pubsub_node{nodeid = {Host, Node},
|
case ParentExists of
|
||||||
parents = Parents, type = Type,
|
true ->
|
||||||
options = Options})
|
case set_node(#pubsub_node{nodeid = {Host, Node},
|
||||||
|
parents = Parents, type = Type,
|
||||||
|
options = Options})
|
||||||
of
|
of
|
||||||
{result, NodeId} -> {ok, NodeId};
|
{result, Nidx} -> {ok, Nidx};
|
||||||
Other -> Other
|
Other -> Other
|
||||||
end;
|
end;
|
||||||
false -> {error, ?ERR_FORBIDDEN}
|
false ->
|
||||||
end;
|
{error, ?ERR_FORBIDDEN}
|
||||||
{result, _} -> {error, ?ERR_CONFLICT};
|
end;
|
||||||
Error -> Error
|
{result, _} ->
|
||||||
|
{error, ?ERR_CONFLICT};
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
end.
|
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) ->
|
delete_node(Host, Node) ->
|
||||||
H = (?PUBSUB):escape(Host),
|
H = node_hometree_odbc:encode_host(Host),
|
||||||
N = (?PUBSUB):escape(Node),
|
N = ejabberd_odbc:escape(Node),
|
||||||
Removed = get_subnodes_tree(Host, Node),
|
Removed = get_subnodes_tree(Host, Node),
|
||||||
catch
|
catch ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
|
||||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
|
H, <<"' and node like '">>, N, <<"%';">>]),
|
||||||
H, <<"' and node like '">>, N, <<"%';">>]),
|
|
||||||
Removed.
|
Removed.
|
||||||
|
|
||||||
%% helpers
|
%% helpers
|
||||||
-spec(raw_to_node/2 ::
|
raw_to_node(Host, [Node, Parent, Type, Nidx]) ->
|
||||||
(
|
|
||||||
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]) ->
|
|
||||||
Options = case catch
|
Options = case catch
|
||||||
ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option "
|
ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option "
|
||||||
"where nodeid='">>,
|
"where nodeid='">>, Nidx, <<"';">>])
|
||||||
NodeIdx, <<"';">>])
|
of
|
||||||
of
|
{selected, [<<"name">>, <<"val">>], ROptions} ->
|
||||||
{selected, [<<"name">>, <<"val">>], ROptions} ->
|
DbOpts = lists:map(fun ([Key, Value]) ->
|
||||||
DbOpts = lists:map(fun ([Key, Value]) ->
|
RKey = jlib:binary_to_atom(Key),
|
||||||
RKey =
|
Tokens = element(2, erl_scan:string(binary_to_list(<<Value/binary, ".">>))),
|
||||||
jlib:binary_to_atom(Key),
|
RValue = element(2, erl_parse:parse_term(Tokens)),
|
||||||
Tokens = element(2,
|
{RKey, RValue}
|
||||||
erl_scan:string(
|
end,
|
||||||
binary_to_list(<<Value/binary, ".">>))),
|
ROptions),
|
||||||
RValue = element(2,
|
Module = jlib:binary_to_atom(<<"node_", Type/binary, "_odbc">>),
|
||||||
erl_parse:parse_term(Tokens)),
|
StdOpts = Module:options(),
|
||||||
{RKey, RValue}
|
lists:foldl(fun ({Key, Value}, Acc) ->
|
||||||
end,
|
lists:keyreplace(Key, 1, Acc, {Key, Value})
|
||||||
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
|
|
||||||
end,
|
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
|
%%% @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>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
|
%%% <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.
|
%%% mod_pubsub, this plugin can not work anymore without altering functioning.
|
||||||
%%% Please, send us comments, feedback and improvements.</p>
|
%%% Please, send us comments, feedback and improvements.</p>
|
||||||
|
|
||||||
-module(nodetree_virtual).
|
-module(nodetree_virtual).
|
||||||
|
-behaviour(gen_pubsub_nodetree).
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-behaviour(gen_pubsub_nodetree).
|
|
||||||
|
|
||||||
-export([init/3, terminate/2, options/0, set_node/1,
|
-export([init/3, terminate/2, options/0, set_node/1,
|
||||||
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
get_node/3, get_node/2, get_node/1, get_nodes/2,
|
||||||
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
|
||||||
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
get_subnodes/3, get_subnodes_tree/3, create_node/6,
|
||||||
delete_node/2]).
|
delete_node/2]).
|
||||||
|
|
||||||
%% ================
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
%% API definition
|
ok.
|
||||||
%% ================
|
|
||||||
|
|
||||||
%% @spec (Host, ServerHost, Opts) -> any()
|
terminate(_Host, _ServerHost) ->
|
||||||
%% Host = mod_pubsub:host()
|
ok.
|
||||||
%% 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.
|
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) ->
|
get_nodes(Host, _From) ->
|
||||||
Record = #pubsub_node{nodeid = NodeId, id = NodeId},
|
get_nodes(Host).
|
||||||
Module = jlib:binary_to_atom(<<"node_",
|
|
||||||
(Record#pubsub_node.type)/binary>>),
|
|
||||||
Options = Module:options(),
|
|
||||||
Owners = [{<<"">>, Host, <<"">>}],
|
|
||||||
Record#pubsub_node{owners = Owners, options = Options}.
|
|
||||||
|
|
||||||
%% @spec (Host, From) -> [pubsubNode()]
|
get_nodes(_Host) ->
|
||||||
%% 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_parentnodes(_Host, _Node, _From) ->
|
||||||
|
[].
|
||||||
|
|
||||||
get_parentnodes(_Host, _Node, _From) -> [].
|
get_parentnodes_tree(Host, Node, From) ->
|
||||||
|
case get_node(Host, Node, From) of
|
||||||
-spec(get_parentnodes_tree/3 ::
|
Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
|
||||||
(
|
_Error -> []
|
||||||
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 -> []
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subnodes(Host, Node, _From) ->
|
get_subnodes(Host, Node, _From) ->
|
||||||
get_subnodes(Host, Node).
|
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, _From) ->
|
||||||
get_subnodes_tree(Host, Node).
|
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,
|
create_node(Host, Node, _Type, _Owner, _Options, _Parents) ->
|
||||||
_Parents) ->
|
|
||||||
{error, {virtual, {Host, Node}}}.
|
{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").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-export([add_subscription/1, read_subscription/1,
|
-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.
|
%% 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.
|
%% They can be enabled again in ejabberd 3.0 because it uses R12B or higher.
|
||||||
%% -spec read_subscription(SubID :: string()) -> {ok, #pubsub_subscription{}} | notfound.
|
%% -spec read_subscription(SubID :: string()) -> {ok, #pubsub_subscription{}} | notfound.
|
||||||
read_subscription(SubID) ->
|
read_subscription(SubID) ->
|
||||||
case
|
case
|
||||||
ejabberd_odbc:sql_query_t([<<"select opt_name, opt_value from pubsub_subscr"
|
ejabberd_odbc:sql_query_t([<<"select opt_name, opt_value from pubsub_subscr"
|
||||||
"iption_opt where subid = '">>,
|
"iption_opt where subid = '">>,
|
||||||
ejabberd_odbc:escape(SubID), <<"'">>])
|
ejabberd_odbc:escape(SubID), <<"'">>])
|
||||||
of
|
of
|
||||||
{selected, [<<"opt_name">>, <<"opt_value">>], []} ->
|
{selected, [<<"opt_name">>, <<"opt_value">>], []} ->
|
||||||
notfound;
|
notfound;
|
||||||
{selected, [<<"opt_name">>, <<"opt_value">>],
|
{selected, [<<"opt_name">>, <<"opt_value">>], Options} ->
|
||||||
Options} ->
|
{ok,
|
||||||
{ok,
|
#pubsub_subscription{subid = SubID,
|
||||||
#pubsub_subscription{subid = SubID,
|
options = lists:map(fun subscription_opt_from_odbc/1, Options)}}
|
||||||
options =
|
|
||||||
lists:map(fun subscription_opt_from_odbc/1,
|
|
||||||
Options)}}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% -spec delete_subscription(SubID :: string()) -> ok.
|
%% -spec delete_subscription(SubID :: string()) -> ok.
|
||||||
delete_subscription(SubID) ->
|
delete_subscription(SubID) ->
|
||||||
%% -spec update_subscription(#pubsub_subscription{}) -> ok .
|
%% -spec update_subscription(#pubsub_subscription{}) -> ok .
|
||||||
%% -spec add_subscription(#pubsub_subscription{}) -> ok.
|
%% -spec add_subscription(#pubsub_subscription{}) -> ok.
|
||||||
%% -------------- Internal utilities -----------------------
|
%% -------------- Internal utilities -----------------------
|
||||||
ejabberd_odbc:sql_query_t([<<"delete from pubsub_subscription_opt "
|
ejabberd_odbc:sql_query_t([<<"delete from pubsub_subscription_opt "
|
||||||
"where subid = '">>,
|
"where subid = '">>,
|
||||||
ejabberd_odbc:escape(SubID), <<"'">>]),
|
ejabberd_odbc:escape(SubID), <<"'">>]),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
update_subscription(#pubsub_subscription{subid =
|
update_subscription(#pubsub_subscription{subid = SubId} = Sub) ->
|
||||||
SubId} =
|
|
||||||
Sub) ->
|
|
||||||
delete_subscription(SubId), add_subscription(Sub).
|
delete_subscription(SubId), add_subscription(Sub).
|
||||||
|
|
||||||
add_subscription(#pubsub_subscription{subid = SubId,
|
add_subscription(#pubsub_subscription{subid = SubId, options = Opts}) ->
|
||||||
options = Opts}) ->
|
|
||||||
EscapedSubId = ejabberd_odbc:escape(SubId),
|
EscapedSubId = ejabberd_odbc:escape(SubId),
|
||||||
lists:foreach(fun (Opt) ->
|
lists:foreach(fun (Opt) ->
|
||||||
{OdbcOptName, OdbcOptValue} =
|
{OdbcOptName, OdbcOptValue} = subscription_opt_to_odbc(Opt),
|
||||||
subscription_opt_to_odbc(Opt),
|
ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, "
|
||||||
ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, "
|
"opt_name, opt_value)values ('">>,
|
||||||
"opt_name, opt_value)values ('">>,
|
EscapedSubId, <<"','">>,
|
||||||
EscapedSubId, <<"','">>,
|
OdbcOptName, <<"','">>,
|
||||||
OdbcOptName, <<"','">>,
|
OdbcOptValue, <<"')">>])
|
||||||
OdbcOptValue, <<"')">>])
|
end,
|
||||||
end,
|
Opts),
|
||||||
Opts),
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
subscription_opt_from_odbc({<<"DELIVER">>, Value}) ->
|
subscription_opt_from_odbc({<<"DELIVER">>, Value}) ->
|
||||||
{deliver, odbc_to_boolean(Value)};
|
{deliver, odbc_to_boolean(Value)};
|
||||||
subscription_opt_from_odbc({<<"DIGEST">>, Value}) ->
|
subscription_opt_from_odbc({<<"DIGEST">>, Value}) ->
|
||||||
{digest, odbc_to_boolean(Value)};
|
{digest, odbc_to_boolean(Value)};
|
||||||
subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>,
|
subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>, Value}) ->
|
||||||
Value}) ->
|
|
||||||
{digest_frequency, odbc_to_integer(Value)};
|
{digest_frequency, odbc_to_integer(Value)};
|
||||||
subscription_opt_from_odbc({<<"EXPIRE">>, Value}) ->
|
subscription_opt_from_odbc({<<"EXPIRE">>, Value}) ->
|
||||||
{expire, odbc_to_timestamp(Value)};
|
{expire, odbc_to_timestamp(Value)};
|
||||||
subscription_opt_from_odbc({<<"INCLUDE_BODY">>,
|
subscription_opt_from_odbc({<<"INCLUDE_BODY">>, Value}) ->
|
||||||
Value}) ->
|
|
||||||
{include_body, odbc_to_boolean(Value)};
|
{include_body, odbc_to_boolean(Value)};
|
||||||
%%TODO: might be > than 1 show_values value??.
|
%%TODO: might be > than 1 show_values value??.
|
||||||
%% need to use compact all in only 1 opt.
|
%% need to use compact all in only 1 opt.
|
||||||
subscription_opt_from_odbc({<<"SHOW_VALUES">>,
|
subscription_opt_from_odbc({<<"SHOW_VALUES">>, Value}) ->
|
||||||
Value}) ->
|
|
||||||
{show_values, Value};
|
{show_values, Value};
|
||||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>,
|
subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>, Value}) ->
|
||||||
Value}) ->
|
|
||||||
{subscription_type,
|
{subscription_type,
|
||||||
case Value of
|
case Value of
|
||||||
<<"items">> -> items;
|
<<"items">> -> items;
|
||||||
<<"nodes">> -> nodes
|
<<"nodes">> -> nodes
|
||||||
end};
|
end};
|
||||||
subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>,
|
subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>, Value}) ->
|
||||||
Value}) ->
|
|
||||||
{subscription_depth,
|
{subscription_depth,
|
||||||
case Value of
|
case Value of
|
||||||
<<"all">> -> all;
|
<<"all">> -> all;
|
||||||
N -> odbc_to_integer(N)
|
N -> odbc_to_integer(N)
|
||||||
end}.
|
end}.
|
||||||
|
|
||||||
subscription_opt_to_odbc({deliver, Bool}) ->
|
subscription_opt_to_odbc({deliver, Bool}) ->
|
||||||
{<<"DELIVER">>, boolean_to_odbc(Bool)};
|
{<<"DELIVER">>, boolean_to_odbc(Bool)};
|
||||||
@ -124,19 +112,18 @@ subscription_opt_to_odbc({show_values, Values}) ->
|
|||||||
{<<"SHOW_VALUES">>, Values};
|
{<<"SHOW_VALUES">>, Values};
|
||||||
subscription_opt_to_odbc({subscription_type, Type}) ->
|
subscription_opt_to_odbc({subscription_type, Type}) ->
|
||||||
{<<"SUBSCRIPTION_TYPE">>,
|
{<<"SUBSCRIPTION_TYPE">>,
|
||||||
case Type of
|
case Type of
|
||||||
items -> <<"items">>;
|
items -> <<"items">>;
|
||||||
nodes -> <<"nodes">>
|
nodes -> <<"nodes">>
|
||||||
end};
|
end};
|
||||||
subscription_opt_to_odbc({subscription_depth, Depth}) ->
|
subscription_opt_to_odbc({subscription_depth, Depth}) ->
|
||||||
{<<"SUBSCRIPTION_DEPTH">>,
|
{<<"SUBSCRIPTION_DEPTH">>,
|
||||||
case Depth of
|
case Depth of
|
||||||
all -> <<"all">>;
|
all -> <<"all">>;
|
||||||
N -> integer_to_odbc(N)
|
N -> integer_to_odbc(N)
|
||||||
end}.
|
end}.
|
||||||
|
|
||||||
integer_to_odbc(N) ->
|
integer_to_odbc(N) -> iolist_to_binary(integer_to_list(N)).
|
||||||
iolist_to_binary(integer_to_list(N)).
|
|
||||||
|
|
||||||
boolean_to_odbc(true) -> <<"1">>;
|
boolean_to_odbc(true) -> <<"1">>;
|
||||||
boolean_to_odbc(false) -> <<"0">>.
|
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_boolean(B) -> B == <<"1">>.
|
||||||
|
|
||||||
odbc_to_timestamp(T) ->
|
odbc_to_timestamp(T) -> jlib:datetime_string_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
|
%% new/1 and free/2 MUST be called inside a transaction bloc
|
||||||
|
|
||||||
-module(pubsub_index).
|
-module(pubsub_index).
|
||||||
|
|
||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
@ -38,30 +37,30 @@
|
|||||||
|
|
||||||
init(_Host, _ServerHost, _Opts) ->
|
init(_Host, _ServerHost, _Opts) ->
|
||||||
mnesia:create_table(pubsub_index,
|
mnesia:create_table(pubsub_index,
|
||||||
[{disc_copies, [node()]},
|
[{disc_copies, [node()]},
|
||||||
{attributes, record_info(fields, pubsub_index)}]).
|
{attributes, record_info(fields, pubsub_index)}]).
|
||||||
|
|
||||||
new(Index) ->
|
new(Index) ->
|
||||||
case mnesia:read({pubsub_index, Index}) of
|
case mnesia:read({pubsub_index, Index}) of
|
||||||
[I] ->
|
[I] ->
|
||||||
case I#pubsub_index.free of
|
case I#pubsub_index.free of
|
||||||
[] ->
|
[] ->
|
||||||
Id = I#pubsub_index.last + 1,
|
Id = I#pubsub_index.last + 1,
|
||||||
mnesia:write(I#pubsub_index{last = Id}),
|
mnesia:write(I#pubsub_index{last = Id}),
|
||||||
Id;
|
Id;
|
||||||
[Id | Free] ->
|
[Id | Free] ->
|
||||||
mnesia:write(I#pubsub_index{free = Free}), Id
|
mnesia:write(I#pubsub_index{free = Free}), Id
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
mnesia:write(#pubsub_index{index = Index, last = 1,
|
mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
|
||||||
free = []}),
|
1
|
||||||
1
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
free(Index, Id) ->
|
free(Index, Id) ->
|
||||||
case mnesia:read({pubsub_index, Index}) of
|
case mnesia:read({pubsub_index, Index}) of
|
||||||
[I] ->
|
[I] ->
|
||||||
Free = I#pubsub_index.free,
|
Free = I#pubsub_index.free,
|
||||||
mnesia:write(I#pubsub_index{free = [Id | Free]});
|
mnesia:write(I#pubsub_index{free = [Id | Free]});
|
||||||
_ -> ok
|
_ ->
|
||||||
|
ok
|
||||||
end.
|
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
|
%% API
|
||||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
||||||
get_subscription/3, set_subscription/4,
|
get_subscription/3, set_subscription/4,
|
||||||
get_options_xform/2, parse_options_xform/1]).
|
get_options_xform/2, parse_options_xform/1]).
|
||||||
|
|
||||||
% Internal function also exported for use in transactional bloc from pubsub plugins
|
% Internal function also exported for use in transactional bloc from pubsub plugins
|
||||||
-export([add_subscription/3, delete_subscription/3,
|
-export([add_subscription/3, delete_subscription/3,
|
||||||
read_subscription/3, write_subscription/4]).
|
read_subscription/3, write_subscription/4]).
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
||||||
|
|
||||||
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
|
-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_EXPIRE, <<"pubsub#expire">>).
|
||||||
|
|
||||||
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
||||||
|
|
||||||
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
||||||
|
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
|
||||||
-define(PUBSUB_SUBSCRIPTION_TYPE,
|
-define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
|
||||||
<<"pubsub#subscription_type">>).
|
-define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
|
||||||
|
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
|
||||||
-define(PUBSUB_SUBSCRIPTION_DEPTH,
|
"(aggregations) of notifications or all notifications individually">>).
|
||||||
<<"pubsub#subscription_depth">>).
|
-define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
|
||||||
|
"sending any two notification digests">>).
|
||||||
-define(DELIVER_LABEL,
|
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
|
||||||
<<"Whether an entity wants to receive or "
|
-define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
|
||||||
"disable notifications">>).
|
"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(DIGEST_LABEL,
|
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
|
||||||
<<"Whether an entity wants to receive digests "
|
-define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
|
||||||
"(aggregations) of notifications or all "
|
-define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
|
||||||
"notifications individually">>).
|
-define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
|
||||||
|
-define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||||
-define(DIGEST_FREQUENCY_LABEL,
|
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
|
||||||
<<"The minimum number of milliseconds between "
|
-define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
|
||||||
"sending any two notification digests">>).
|
-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(EXPIRE_LABEL,
|
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
|
||||||
<<"The DateTime at which a leased subscription "
|
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
|
||||||
"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
|
%% API
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
init() -> ok = create_table().
|
init() -> ok = create_table().
|
||||||
|
|
||||||
subscribe_node(JID, NodeID, Options) ->
|
subscribe_node(JID, NodeId, Options) ->
|
||||||
case catch mnesia:sync_dirty(fun add_subscription/3,
|
case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options])
|
||||||
[JID, NodeID, Options])
|
of
|
||||||
of
|
{'EXIT', {aborted, Error}} -> Error;
|
||||||
{'EXIT', {aborted, Error}} -> Error;
|
{error, Error} -> {error, Error};
|
||||||
{error, Error} -> {error, Error};
|
Result -> {result, Result}
|
||||||
Result -> {result, Result}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
unsubscribe_node(JID, NodeID, SubID) ->
|
unsubscribe_node(JID, NodeId, SubID) ->
|
||||||
case catch mnesia:sync_dirty(fun delete_subscription/3,
|
case catch mnesia:sync_dirty(fun delete_subscription/3, [JID, NodeId, SubID])
|
||||||
[JID, NodeID, SubID])
|
of
|
||||||
of
|
{'EXIT', {aborted, Error}} -> Error;
|
||||||
{'EXIT', {aborted, Error}} -> Error;
|
{error, Error} -> {error, Error};
|
||||||
{error, Error} -> {error, Error};
|
Result -> {result, Result}
|
||||||
Result -> {result, Result}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subscription(JID, NodeID, SubID) ->
|
get_subscription(JID, NodeId, SubID) ->
|
||||||
case catch mnesia:sync_dirty(fun read_subscription/3,
|
case catch mnesia:sync_dirty(fun read_subscription/3, [JID, NodeId, SubID])
|
||||||
[JID, NodeID, SubID])
|
of
|
||||||
of
|
{'EXIT', {aborted, Error}} -> Error;
|
||||||
{'EXIT', {aborted, Error}} -> Error;
|
{error, Error} -> {error, Error};
|
||||||
{error, Error} -> {error, Error};
|
Result -> {result, Result}
|
||||||
Result -> {result, Result}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_subscription(JID, NodeID, SubID, Options) ->
|
set_subscription(JID, NodeId, SubID, Options) ->
|
||||||
case catch mnesia:sync_dirty(fun write_subscription/4,
|
case catch mnesia:sync_dirty(fun write_subscription/4, [JID, NodeId, SubID, Options])
|
||||||
[JID, NodeID, SubID, Options])
|
of
|
||||||
of
|
{'EXIT', {aborted, Error}} -> Error;
|
||||||
{'EXIT', {aborted, Error}} -> Error;
|
{error, Error} -> {error, Error};
|
||||||
{error, Error} -> {error, Error};
|
Result -> {result, Result}
|
||||||
Result -> {result, Result}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
get_options_xform(Lang, Options) ->
|
get_options_xform(Lang, Options) ->
|
||||||
Keys = [deliver, show_values, subscription_type,
|
Keys = [deliver, show_values, subscription_type, subscription_depth],
|
||||||
subscription_depth],
|
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|
||||||
XFields = [get_option_xfield(Lang, Key, Options)
|
|
||||||
|| Key <- Keys],
|
|
||||||
{result,
|
{result,
|
||||||
#xmlel{name = <<"x">>,
|
#xmlel{name = <<"x">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"field">>,
|
[#xmlel{name = <<"field">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"var">>, <<"FORM_TYPE">>},
|
[{<<"var">>, <<"FORM_TYPE">>},
|
||||||
{<<"type">>, <<"hidden">>}],
|
{<<"type">>, <<"hidden">>}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"value">>, attrs = [],
|
[#xmlel{name = <<"value">>, attrs = [],
|
||||||
children =
|
children =
|
||||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||||
++ XFields}}.
|
++ XFields}}.
|
||||||
|
|
||||||
parse_options_xform(XFields) ->
|
parse_options_xform(XFields) ->
|
||||||
case xml:remove_cdata(XFields) of
|
case xml:remove_cdata(XFields) of
|
||||||
[#xmlel{name = <<"x">>} = XEl] ->
|
[#xmlel{name = <<"x">>} = XEl] ->
|
||||||
case jlib:parse_xdata_submit(XEl) of
|
case jlib:parse_xdata_submit(XEl) of
|
||||||
XData when is_list(XData) ->
|
XData when is_list(XData) ->
|
||||||
Opts = set_xoption(XData, []),
|
Opts = set_xoption(XData, []),
|
||||||
{result, Opts};
|
{result, Opts};
|
||||||
Other -> Other
|
Other -> Other
|
||||||
end;
|
end;
|
||||||
_ -> {result, []}
|
_ -> {result, []}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -196,69 +138,67 @@ parse_options_xform(XFields) ->
|
|||||||
%%====================================================================
|
%%====================================================================
|
||||||
create_table() ->
|
create_table() ->
|
||||||
case mnesia:create_table(pubsub_subscription,
|
case mnesia:create_table(pubsub_subscription,
|
||||||
[{disc_copies, [node()]},
|
[{disc_copies, [node()]},
|
||||||
{attributes,
|
{attributes,
|
||||||
record_info(fields, pubsub_subscription)},
|
record_info(fields, pubsub_subscription)},
|
||||||
{type, set}])
|
{type, set}])
|
||||||
of
|
of
|
||||||
{atomic, ok} -> ok;
|
{atomic, ok} -> ok;
|
||||||
{aborted, {already_exists, _}} -> ok;
|
{aborted, {already_exists, _}} -> ok;
|
||||||
Other -> Other
|
Other -> Other
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(add_subscription/3 ::
|
-spec(add_subscription/3 ::
|
||||||
(
|
(
|
||||||
_JID :: ljid(),
|
_JID :: ljid(),
|
||||||
_NodeID :: mod_pubsub:nodeIdx(),
|
_NodeId :: mod_pubsub:nodeIdx(),
|
||||||
Options :: [] | mod_pubsub:subOptions())
|
Options :: [] | mod_pubsub:subOptions())
|
||||||
-> SubId :: mod_pubsub:subId()
|
-> SubId :: mod_pubsub:subId()
|
||||||
).
|
).
|
||||||
|
|
||||||
add_subscription(_JID, _NodeID, []) -> make_subid();
|
add_subscription(_JID, _NodeId, []) -> make_subid();
|
||||||
add_subscription(_JID, _NodeID, Options) ->
|
add_subscription(_JID, _NodeId, Options) ->
|
||||||
SubID = make_subid(),
|
SubID = make_subid(),
|
||||||
mnesia:write(#pubsub_subscription{subid = SubID,
|
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}),
|
||||||
options = Options}),
|
|
||||||
SubID.
|
SubID.
|
||||||
|
|
||||||
-spec(delete_subscription/3 ::
|
-spec(delete_subscription/3 ::
|
||||||
(
|
(
|
||||||
_JID :: _,
|
_JID :: _,
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubId :: mod_pubsub:subId())
|
SubId :: mod_pubsub:subId())
|
||||||
-> ok
|
-> ok
|
||||||
).
|
).
|
||||||
|
|
||||||
delete_subscription(_JID, _NodeID, SubID) ->
|
delete_subscription(_JID, _NodeId, SubID) ->
|
||||||
mnesia:delete({pubsub_subscription, SubID}).
|
mnesia:delete({pubsub_subscription, SubID}).
|
||||||
|
|
||||||
-spec(read_subscription/3 ::
|
-spec(read_subscription/3 ::
|
||||||
(
|
(
|
||||||
_JID :: ljid(),
|
_JID :: ljid(),
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubID :: mod_pubsub:subId())
|
SubID :: mod_pubsub:subId())
|
||||||
-> mod_pubsub:pubsubSubscription()
|
-> mod_pubsub:pubsubSubscription()
|
||||||
| {error, notfound}
|
| {error, notfound}
|
||||||
).
|
).
|
||||||
|
|
||||||
read_subscription(_JID, _NodeID, SubID) ->
|
read_subscription(_JID, _NodeId, SubID) ->
|
||||||
case mnesia:read({pubsub_subscription, SubID}) of
|
case mnesia:read({pubsub_subscription, SubID}) of
|
||||||
[Sub] -> Sub;
|
[Sub] -> Sub;
|
||||||
_ -> {error, notfound}
|
_ -> {error, notfound}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(write_subscription/4 ::
|
-spec(write_subscription/4 ::
|
||||||
(
|
(
|
||||||
_JID :: ljid(),
|
_JID :: ljid(),
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubID :: mod_pubsub:subId(),
|
SubID :: mod_pubsub:subId(),
|
||||||
Options :: mod_pubsub:subOptions())
|
Options :: mod_pubsub:subOptions())
|
||||||
-> ok
|
-> ok
|
||||||
).
|
).
|
||||||
|
|
||||||
write_subscription(_JID, _NodeID, SubID, Options) ->
|
write_subscription(_JID, _NodeId, SubID, Options) ->
|
||||||
mnesia:write(#pubsub_subscription{subid = SubID,
|
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}).
|
||||||
options = Options}).
|
|
||||||
|
|
||||||
-spec(make_subid/0 :: () -> SubId::mod_pubsub:subId()).
|
-spec(make_subid/0 :: () -> SubId::mod_pubsub:subId()).
|
||||||
make_subid() ->
|
make_subid() ->
|
||||||
@ -274,43 +214,42 @@ make_subid() ->
|
|||||||
set_xoption([], Opts) -> Opts;
|
set_xoption([], Opts) -> Opts;
|
||||||
set_xoption([{Var, Value} | T], Opts) ->
|
set_xoption([{Var, Value} | T], Opts) ->
|
||||||
NewOpts = case var_xfield(Var) of
|
NewOpts = case var_xfield(Var) of
|
||||||
{error, _} -> Opts;
|
{error, _} -> Opts;
|
||||||
Key ->
|
Key ->
|
||||||
Val = val_xfield(Key, Value),
|
Val = val_xfield(Key, Value),
|
||||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||||
end,
|
end,
|
||||||
set_xoption(T, NewOpts).
|
set_xoption(T, NewOpts).
|
||||||
|
|
||||||
%% Return the options list's key for an XForm var.
|
%% Return the options list's key for an XForm var.
|
||||||
%% Convert Values for option list's Key.
|
%% Convert Values for option list's Key.
|
||||||
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
||||||
var_xfield(?PUBSUB_DIGEST) -> digest;
|
var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) ->
|
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
|
||||||
digest_frequency;
|
|
||||||
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||||
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||||
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
||||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) ->
|
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
|
||||||
subscription_type;
|
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
|
||||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
|
|
||||||
subscription_depth;
|
|
||||||
var_xfield(_) -> {error, badarg}.
|
var_xfield(_) -> {error, badarg}.
|
||||||
|
|
||||||
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
||||||
%val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||||
%val_xfield(digest_frequency, [Val]) ->
|
val_xfield(digest_frequency, [Val]) ->
|
||||||
% jlib:binary_to_integer(Val);
|
case catch jlib:binary_to_integer(Val) of
|
||||||
%val_xfield(expire, [Val]) ->
|
N when is_integer(N) -> N;
|
||||||
% jlib:datetime_string_to_timestamp(Val);
|
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||||
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
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(show_values, Vals) -> Vals;
|
||||||
val_xfield(subscription_type, [<<"items">>]) -> items;
|
val_xfield(subscription_type, [<<"items">>]) -> items;
|
||||||
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
||||||
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
||||||
val_xfield(subscription_depth, [Depth]) ->
|
val_xfield(subscription_depth, [Depth]) ->
|
||||||
case catch jlib:binary_to_integer(Depth) of
|
case catch jlib:binary_to_integer(Depth) of
|
||||||
N when is_integer(N) -> N;
|
N when is_integer(N) -> N;
|
||||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Convert XForm booleans to Erlang booleans.
|
%% Convert XForm booleans to Erlang booleans.
|
||||||
@ -321,31 +260,30 @@ xopt_to_bool(<<"true">>) -> true;
|
|||||||
xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
|
xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
|
||||||
|
|
||||||
-spec(get_option_xfield/3 ::
|
-spec(get_option_xfield/3 ::
|
||||||
(
|
(
|
||||||
Lang :: binary(),
|
Lang :: binary(),
|
||||||
Key :: atom(),
|
Key :: atom(),
|
||||||
Options :: mod_pubsub:subOptions())
|
Options :: mod_pubsub:subOptions())
|
||||||
-> xmlel()
|
-> xmlel()
|
||||||
).
|
).
|
||||||
|
|
||||||
%% Return a field for an XForm for Key, with data filled in, if
|
%% Return a field for an XForm for Key, with data filled in, if
|
||||||
%% applicable, from Options.
|
%% applicable, from Options.
|
||||||
get_option_xfield(Lang, Key, Options) ->
|
get_option_xfield(Lang, Key, Options) ->
|
||||||
Var = xfield_var(Key),
|
Var = xfield_var(Key),
|
||||||
Label = xfield_label(Key),
|
Label = xfield_label(Key),
|
||||||
{Type, OptEls} = type_and_options(xfield_type(Key),
|
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
|
||||||
Lang),
|
|
||||||
Vals = case lists:keysearch(Key, 1, Options) of
|
Vals = case lists:keysearch(Key, 1, Options) of
|
||||||
{value, {_, Val}} ->
|
{value, {_, Val}} ->
|
||||||
[tr_xfield_values(Vals)
|
[tr_xfield_values(Vals)
|
||||||
|| Vals <- xfield_val(Key, Val)];
|
|| Vals <- xfield_val(Key, Val)];
|
||||||
false -> []
|
false -> []
|
||||||
end,
|
end,
|
||||||
#xmlel{name = <<"field">>,
|
#xmlel{name = <<"field">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||||
{<<"label">>, translate:translate(Lang, Label)}],
|
{<<"label">>, translate:translate(Lang, Label)}],
|
||||||
children = OptEls ++ Vals}.
|
children = OptEls ++ Vals}.
|
||||||
|
|
||||||
type_and_options({Type, Options}, Lang) ->
|
type_and_options({Type, Options}, Lang) ->
|
||||||
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
||||||
@ -353,42 +291,26 @@ type_and_options(Type, _Lang) -> {Type, []}.
|
|||||||
|
|
||||||
tr_xfield_options({Value, Label}, Lang) ->
|
tr_xfield_options({Value, Label}, Lang) ->
|
||||||
#xmlel{name = <<"option">>,
|
#xmlel{name = <<"option">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"value">>, attrs = [],
|
[#xmlel{name = <<"value">>, attrs = [],
|
||||||
children = [{xmlcdata, Value}]}]}.
|
children = [{xmlcdata, Value}]}]}.
|
||||||
|
|
||||||
tr_xfield_values(Value) ->
|
tr_xfield_values(Value) ->
|
||||||
%% Return the XForm variable name 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.
|
%% Return the XForm variable type for a subscription option key.
|
||||||
#xmlel{name = <<"value">>, attrs = [],
|
#xmlel{name = <<"value">>, attrs = [],
|
||||||
children = [{xmlcdata, Value}]}.
|
children = [{xmlcdata, Value}]}.
|
||||||
|
|
||||||
-spec(xfield_var/1 ::
|
|
||||||
(
|
|
||||||
Var :: 'deliver'
|
|
||||||
% | 'digest'
|
|
||||||
% | 'digest_frequency'
|
|
||||||
% | 'expire'
|
|
||||||
% | 'include_body'
|
|
||||||
| 'show_values'
|
|
||||||
| 'subscription_type'
|
|
||||||
| 'subscription_depth')
|
|
||||||
-> binary()
|
|
||||||
).
|
|
||||||
|
|
||||||
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
||||||
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
||||||
%xfield_var(digest_frequency) ->
|
%xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||||
% ?PUBSUB_DIGEST_FREQUENCY;
|
|
||||||
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
||||||
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
||||||
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
||||||
xfield_var(subscription_type) ->
|
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||||
?PUBSUB_SUBSCRIPTION_TYPE;
|
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||||
xfield_var(subscription_depth) ->
|
|
||||||
?PUBSUB_SUBSCRIPTION_DEPTH.
|
|
||||||
|
|
||||||
xfield_type(deliver) -> <<"boolean">>;
|
xfield_type(deliver) -> <<"boolean">>;
|
||||||
%xfield_type(digest) -> <<"boolean">>;
|
%xfield_type(digest) -> <<"boolean">>;
|
||||||
@ -397,52 +319,31 @@ xfield_type(deliver) -> <<"boolean">>;
|
|||||||
%xfield_type(include_body) -> <<"boolean">>;
|
%xfield_type(include_body) -> <<"boolean">>;
|
||||||
xfield_type(show_values) ->
|
xfield_type(show_values) ->
|
||||||
{<<"list-multi">>,
|
{<<"list-multi">>,
|
||||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||||
xfield_type(subscription_type) ->
|
xfield_type(subscription_type) ->
|
||||||
{<<"list-single">>,
|
{<<"list-single">>,
|
||||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||||
xfield_type(subscription_depth) ->
|
xfield_type(subscription_depth) ->
|
||||||
{<<"list-single">>,
|
{<<"list-single">>,
|
||||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||||
|
|
||||||
%% Return the XForm variable label for a subscription option key.
|
%% Return the XForm variable label for a subscription option key.
|
||||||
xfield_label(deliver) -> ?DELIVER_LABEL;
|
xfield_label(deliver) -> ?DELIVER_LABEL;
|
||||||
%xfield_label(digest) -> ?DIGEST_LABEL;
|
%xfield_label(digest) -> ?DIGEST_LABEL;
|
||||||
%xfield_label(digest_frequency) ->
|
%xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
|
||||||
% ?DIGEST_FREQUENCY_LABEL;
|
|
||||||
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
||||||
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
||||||
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
||||||
%% Return the XForm value for a subscription option key.
|
%% Return the XForm value for a subscription option key.
|
||||||
%% Convert erlang booleans to XForms.
|
%% Convert erlang booleans to XForms.
|
||||||
xfield_label(subscription_type) ->
|
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||||
?SUBSCRIPTION_TYPE_LABEL;
|
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_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_val(deliver, Val) -> [bool_to_xopt(Val)];
|
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||||
%xfield_val(digest, 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))];
|
% [iolist_to_binary(integer_to_list(Val))];
|
||||||
%xfield_val(expire, Val) ->
|
%xfield_val(expire, Val) ->
|
||||||
% [jlib:now_to_utc_string(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(show_values, Val) -> Val;
|
||||||
xfield_val(subscription_type, items) -> [<<"items">>];
|
xfield_val(subscription_type, items) -> [<<"items">>];
|
||||||
xfield_val(subscription_type, nodes) -> [<<"nodes">>];
|
xfield_val(subscription_type, nodes) -> [<<"nodes">>];
|
||||||
|
@ -22,98 +22,45 @@
|
|||||||
%%% ====================================================================
|
%%% ====================================================================
|
||||||
|
|
||||||
-module(pubsub_subscription_odbc).
|
-module(pubsub_subscription_odbc).
|
||||||
|
|
||||||
-author("pablo.polvorin@process-one.net").
|
-author("pablo.polvorin@process-one.net").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
-export([init/0, subscribe_node/3, unsubscribe_node/3,
|
||||||
get_subscription/3, set_subscription/4,
|
get_subscription/3, set_subscription/4,
|
||||||
get_options_xform/2, parse_options_xform/1]).
|
get_options_xform/2, parse_options_xform/1]).
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
|
||||||
|
|
||||||
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
|
-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_EXPIRE, <<"pubsub#expire">>).
|
||||||
|
|
||||||
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
|
||||||
|
|
||||||
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
|
||||||
|
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
|
||||||
-define(PUBSUB_SUBSCRIPTION_TYPE,
|
-define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
|
||||||
<<"pubsub#subscription_type">>).
|
-define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
|
||||||
|
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
|
||||||
-define(PUBSUB_SUBSCRIPTION_DEPTH,
|
"(aggregations) of notifications or all notifications individually">>).
|
||||||
<<"pubsub#subscription_depth">>).
|
-define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
|
||||||
|
"sending any two notification digests">>).
|
||||||
-define(DELIVER_LABEL,
|
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
|
||||||
<<"Whether an entity wants to receive or "
|
-define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
|
||||||
"disable notifications">>).
|
"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(DIGEST_LABEL,
|
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
|
||||||
<<"Whether an entity wants to receive digests "
|
-define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
|
||||||
"(aggregations) of notifications or all "
|
-define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
|
||||||
"notifications individually">>).
|
-define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
|
||||||
|
-define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
|
||||||
-define(DIGEST_FREQUENCY_LABEL,
|
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
|
||||||
<<"The minimum number of milliseconds between "
|
-define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
|
||||||
"sending any two notification digests">>).
|
-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(EXPIRE_LABEL,
|
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
|
||||||
<<"The DateTime at which a leased subscription "
|
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
|
||||||
"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).
|
-define(DB_MOD, pubsub_db_odbc).
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -123,99 +70,92 @@
|
|||||||
init() -> ok = create_table().
|
init() -> ok = create_table().
|
||||||
|
|
||||||
-spec(subscribe_node/3 ::
|
-spec(subscribe_node/3 ::
|
||||||
(
|
(
|
||||||
_JID :: _,
|
_JID :: _,
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
Options :: mod_pubsub:subOptions())
|
Options :: [] | mod_pubsub:subOptions())
|
||||||
-> {result, mod_pubsub:subId()}
|
-> {result, mod_pubsub:subId()}
|
||||||
).
|
).
|
||||||
subscribe_node(_JID, _NodeID, Options) ->
|
subscribe_node(_JID, _NodeId, Options) ->
|
||||||
SubID = make_subid(),
|
SubID = make_subid(),
|
||||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid =
|
(?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID, options = Options}),
|
||||||
SubID,
|
|
||||||
options = Options}),
|
|
||||||
{result, SubID}.
|
{result, SubID}.
|
||||||
|
|
||||||
-spec(unsubscribe_node/3 ::
|
-spec(unsubscribe_node/3 ::
|
||||||
(
|
(
|
||||||
_JID :: _,
|
_JID :: _,
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubID :: mod_pubsub:subId())
|
SubID :: mod_pubsub:subId())
|
||||||
-> {result, mod_pubsub:subscription()}
|
-> {result, mod_pubsub:subscription()}
|
||||||
| {error, notfound}
|
| {error, notfound}
|
||||||
).
|
).
|
||||||
unsubscribe_node(_JID, _NodeID, SubID) ->
|
unsubscribe_node(_JID, _NodeId, SubID) ->
|
||||||
case (?DB_MOD):read_subscription(SubID) of
|
case (?DB_MOD):read_subscription(SubID) of
|
||||||
{ok, Sub} ->
|
{ok, Sub} -> (?DB_MOD):delete_subscription(SubID), {result, Sub};
|
||||||
(?DB_MOD):delete_subscription(SubID), {result, Sub};
|
notfound -> {error, notfound}
|
||||||
notfound -> {error, notfound}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(get_subscription/3 ::
|
-spec(get_subscription/3 ::
|
||||||
(
|
(
|
||||||
_JID :: _,
|
_JID :: _,
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubId :: mod_pubsub:subId())
|
SubId :: mod_pubsub:subId())
|
||||||
-> {result, mod_pubsub:subscription()}
|
-> {result, mod_pubsub:subscription()}
|
||||||
| {error, notfound}
|
| {error, notfound}
|
||||||
).
|
).
|
||||||
get_subscription(_JID, _NodeID, SubID) ->
|
get_subscription(_JID, _NodeId, SubID) ->
|
||||||
case (?DB_MOD):read_subscription(SubID) of
|
case (?DB_MOD):read_subscription(SubID) of
|
||||||
{ok, Sub} -> {result, Sub};
|
{ok, Sub} -> {result, Sub};
|
||||||
notfound -> {error, notfound}
|
notfound -> {error, notfound}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(set_subscription/4 ::
|
-spec(set_subscription/4 ::
|
||||||
(
|
(
|
||||||
_JID :: _,
|
_JID :: _,
|
||||||
_NodeID :: _,
|
_NodeId :: _,
|
||||||
SubId :: mod_pubsub:subId(),
|
SubId :: mod_pubsub:subId(),
|
||||||
Options :: mod_pubsub:subOptions())
|
Options :: mod_pubsub:subOptions())
|
||||||
-> {result, ok}
|
-> {result, ok}
|
||||||
).
|
).
|
||||||
set_subscription(_JID, _NodeID, SubID, Options) ->
|
set_subscription(_JID, _NodeId, SubID, Options) ->
|
||||||
case (?DB_MOD):read_subscription(SubID) of
|
case (?DB_MOD):read_subscription(SubID) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
(?DB_MOD):update_subscription(#pubsub_subscription{subid
|
(?DB_MOD):update_subscription(#pubsub_subscription{subid = SubID,
|
||||||
= SubID,
|
options = Options}),
|
||||||
options =
|
{result, ok};
|
||||||
Options}),
|
notfound ->
|
||||||
{result, ok};
|
(?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID,
|
||||||
notfound ->
|
options = Options}),
|
||||||
(?DB_MOD):add_subscription(#pubsub_subscription{subid =
|
{result, ok}
|
||||||
SubID,
|
|
||||||
options = Options}),
|
|
||||||
{result, ok}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_options_xform(Lang, Options) ->
|
get_options_xform(Lang, Options) ->
|
||||||
Keys = [deliver, show_values, subscription_type, subscription_depth],
|
Keys = [deliver, show_values, subscription_type, subscription_depth],
|
||||||
XFields = [get_option_xfield(Lang, Key, Options)
|
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|
||||||
|| Key <- Keys],
|
|
||||||
{result,
|
{result,
|
||||||
#xmlel{name = <<"x">>,
|
#xmlel{name = <<"x">>,
|
||||||
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
attrs = [{<<"xmlns">>, ?NS_XDATA}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"field">>,
|
[#xmlel{name = <<"field">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"var">>, <<"FORM_TYPE">>},
|
[{<<"var">>, <<"FORM_TYPE">>},
|
||||||
{<<"type">>, <<"hidden">>}],
|
{<<"type">>, <<"hidden">>}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"value">>, attrs = [],
|
[#xmlel{name = <<"value">>, attrs = [],
|
||||||
children =
|
children =
|
||||||
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
[{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
|
||||||
++ XFields}}.
|
++ XFields}}.
|
||||||
|
|
||||||
parse_options_xform(XFields) ->
|
parse_options_xform(XFields) ->
|
||||||
case xml:remove_cdata(XFields) of
|
case xml:remove_cdata(XFields) of
|
||||||
[#xmlel{name = <<"x">>} = XEl] ->
|
[#xmlel{name = <<"x">>} = XEl] ->
|
||||||
case jlib:parse_xdata_submit(XEl) of
|
case jlib:parse_xdata_submit(XEl) of
|
||||||
XData when is_list(XData) ->
|
XData when is_list(XData) ->
|
||||||
Opts = set_xoption(XData, []),
|
Opts = set_xoption(XData, []),
|
||||||
{result, Opts};
|
{result, Opts};
|
||||||
Other -> Other
|
Other -> Other
|
||||||
end;
|
end;
|
||||||
_ -> {result, []}
|
_ -> {result, []}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
@ -237,43 +177,42 @@ make_subid() ->
|
|||||||
set_xoption([], Opts) -> Opts;
|
set_xoption([], Opts) -> Opts;
|
||||||
set_xoption([{Var, Value} | T], Opts) ->
|
set_xoption([{Var, Value} | T], Opts) ->
|
||||||
NewOpts = case var_xfield(Var) of
|
NewOpts = case var_xfield(Var) of
|
||||||
{error, _} -> Opts;
|
{error, _} -> Opts;
|
||||||
Key ->
|
Key ->
|
||||||
Val = val_xfield(Key, Value),
|
Val = val_xfield(Key, Value),
|
||||||
lists:keystore(Key, 1, Opts, {Key, Val})
|
lists:keystore(Key, 1, Opts, {Key, Val})
|
||||||
end,
|
end,
|
||||||
set_xoption(T, NewOpts).
|
set_xoption(T, NewOpts).
|
||||||
|
|
||||||
%% Return the options list's key for an XForm var.
|
%% Return the options list's key for an XForm var.
|
||||||
%% Convert Values for option list's Key.
|
%% Convert Values for option list's Key.
|
||||||
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
||||||
%var_xfield(?PUBSUB_DIGEST) -> digest;
|
var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||||
%var_xfield(?PUBSUB_DIGEST_FREQUENCY) ->
|
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
|
||||||
% digest_frequency;
|
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||||
%var_xfield(?PUBSUB_EXPIRE) -> expire;
|
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||||
%var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
|
||||||
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
||||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) ->
|
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
|
||||||
subscription_type;
|
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
|
||||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
|
|
||||||
subscription_depth;
|
|
||||||
var_xfield(_) -> {error, badarg}.
|
var_xfield(_) -> {error, badarg}.
|
||||||
|
|
||||||
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
||||||
%val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||||
%val_xfield(digest_frequency, [Val]) ->
|
val_xfield(digest_frequency, [Val]) ->
|
||||||
% jlib:binary_to_integer(Val);
|
case catch jlib:binary_to_integer(Val) of
|
||||||
%val_xfield(expire, [Val]) ->
|
N when is_integer(N) -> N;
|
||||||
% jlib:datetime_string_to_timestamp(Val);
|
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||||
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
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(show_values, Vals) -> Vals;
|
||||||
val_xfield(subscription_type, [<<"items">>]) -> items;
|
val_xfield(subscription_type, [<<"items">>]) -> items;
|
||||||
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
|
||||||
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
val_xfield(subscription_depth, [<<"all">>]) -> all;
|
||||||
val_xfield(subscription_depth, [Depth]) ->
|
val_xfield(subscription_depth, [Depth]) ->
|
||||||
case catch jlib:binary_to_integer(Depth) of
|
case catch jlib:binary_to_integer(Depth) of
|
||||||
N when is_integer(N) -> N;
|
N when is_integer(N) -> N;
|
||||||
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
_ -> {error, ?ERR_NOT_ACCEPTABLE}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Convert XForm booleans to Erlang booleans.
|
%% Convert XForm booleans to Erlang booleans.
|
||||||
@ -288,19 +227,18 @@ xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
|
|||||||
get_option_xfield(Lang, Key, Options) ->
|
get_option_xfield(Lang, Key, Options) ->
|
||||||
Var = xfield_var(Key),
|
Var = xfield_var(Key),
|
||||||
Label = xfield_label(Key),
|
Label = xfield_label(Key),
|
||||||
{Type, OptEls} = type_and_options(xfield_type(Key),
|
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
|
||||||
Lang),
|
|
||||||
Vals = case lists:keysearch(Key, 1, Options) of
|
Vals = case lists:keysearch(Key, 1, Options) of
|
||||||
{value, {_, Val}} ->
|
{value, {_, Val}} ->
|
||||||
[tr_xfield_values(Vals)
|
[tr_xfield_values(Vals)
|
||||||
|| Vals <- xfield_val(Key, Val)];
|
|| Vals <- xfield_val(Key, Val)];
|
||||||
false -> []
|
false -> []
|
||||||
end,
|
end,
|
||||||
#xmlel{name = <<"field">>,
|
#xmlel{name = <<"field">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"var">>, Var}, {<<"type">>, Type},
|
[{<<"var">>, Var}, {<<"type">>, Type},
|
||||||
{<<"label">>, translate:translate(Lang, Label)}],
|
{<<"label">>, translate:translate(Lang, Label)}],
|
||||||
children = OptEls ++ Vals}.
|
children = OptEls ++ Vals}.
|
||||||
|
|
||||||
type_and_options({Type, Options}, Lang) ->
|
type_and_options({Type, Options}, Lang) ->
|
||||||
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
||||||
@ -308,29 +246,26 @@ type_and_options(Type, _Lang) -> {Type, []}.
|
|||||||
|
|
||||||
tr_xfield_options({Value, Label}, Lang) ->
|
tr_xfield_options({Value, Label}, Lang) ->
|
||||||
#xmlel{name = <<"option">>,
|
#xmlel{name = <<"option">>,
|
||||||
attrs =
|
attrs =
|
||||||
[{<<"label">>, translate:translate(Lang, Label)}],
|
[{<<"label">>, translate:translate(Lang, Label)}],
|
||||||
children =
|
children =
|
||||||
[#xmlel{name = <<"value">>, attrs = [],
|
[#xmlel{name = <<"value">>, attrs = [],
|
||||||
children = [{xmlcdata, Value}]}]}.
|
children = [{xmlcdata, Value}]}]}.
|
||||||
|
|
||||||
tr_xfield_values(Value) ->
|
tr_xfield_values(Value) ->
|
||||||
%% Return the XForm variable name 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.
|
%% Return the XForm variable type for a subscription option key.
|
||||||
#xmlel{name = <<"value">>, attrs = [],
|
#xmlel{name = <<"value">>, attrs = [],
|
||||||
children = [{xmlcdata, Value}]}.
|
children = [{xmlcdata, Value}]}.
|
||||||
|
|
||||||
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
||||||
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
%xfield_var(digest) -> ?PUBSUB_DIGEST;
|
||||||
%xfield_var(digest_frequency) ->
|
%xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||||
% ?PUBSUB_DIGEST_FREQUENCY;
|
|
||||||
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
%xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
||||||
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
||||||
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
||||||
xfield_var(subscription_type) ->
|
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||||
?PUBSUB_SUBSCRIPTION_TYPE;
|
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||||
xfield_var(subscription_depth) ->
|
|
||||||
?PUBSUB_SUBSCRIPTION_DEPTH.
|
|
||||||
|
|
||||||
xfield_type(deliver) -> <<"boolean">>;
|
xfield_type(deliver) -> <<"boolean">>;
|
||||||
%xfield_type(digest) -> <<"boolean">>;
|
%xfield_type(digest) -> <<"boolean">>;
|
||||||
@ -339,34 +274,31 @@ xfield_type(deliver) -> <<"boolean">>;
|
|||||||
%xfield_type(include_body) -> <<"boolean">>;
|
%xfield_type(include_body) -> <<"boolean">>;
|
||||||
xfield_type(show_values) ->
|
xfield_type(show_values) ->
|
||||||
{<<"list-multi">>,
|
{<<"list-multi">>,
|
||||||
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
|
||||||
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
|
||||||
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
|
||||||
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
|
||||||
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
|
||||||
xfield_type(subscription_type) ->
|
xfield_type(subscription_type) ->
|
||||||
{<<"list-single">>,
|
{<<"list-single">>,
|
||||||
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||||
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||||
xfield_type(subscription_depth) ->
|
xfield_type(subscription_depth) ->
|
||||||
{<<"list-single">>,
|
{<<"list-single">>,
|
||||||
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||||
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||||
|
|
||||||
%% Return the XForm variable label for a subscription option key.
|
%% Return the XForm variable label for a subscription option key.
|
||||||
xfield_label(deliver) -> ?DELIVER_LABEL;
|
xfield_label(deliver) -> ?DELIVER_LABEL;
|
||||||
%xfield_label(digest) -> ?DIGEST_LABEL;
|
%xfield_label(digest) -> ?DIGEST_LABEL;
|
||||||
%xfield_label(digest_frequency) ->
|
%xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
|
||||||
% ?DIGEST_FREQUENCY_LABEL;
|
|
||||||
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
%xfield_label(expire) -> ?EXPIRE_LABEL;
|
||||||
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
||||||
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
||||||
%% Return the XForm value for a subscription option key.
|
%% Return the XForm value for a subscription option key.
|
||||||
%% Convert erlang booleans to XForms.
|
%% Convert erlang booleans to XForms.
|
||||||
xfield_label(subscription_type) ->
|
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||||
?SUBSCRIPTION_TYPE_LABEL;
|
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
|
||||||
xfield_label(subscription_depth) ->
|
|
||||||
?SUBSCRIPTION_DEPTH_LABEL.
|
|
||||||
|
|
||||||
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||||
%xfield_val(digest, Val) -> [bool_to_xopt(Val)];
|
%xfield_val(digest, Val) -> [bool_to_xopt(Val)];
|
||||||
|
@ -813,7 +813,7 @@ pubsub(Config) ->
|
|||||||
node = Node,
|
node = Node,
|
||||||
jid = my_jid(Config)}}]}),
|
jid = my_jid(Config)}}]}),
|
||||||
?recv2(
|
?recv2(
|
||||||
#message{sub_els = [#pubsub_event{}, #delay{}, #legacy_delay{}]},
|
#message{sub_els = [#pubsub_event{}, #delay{}]},
|
||||||
#iq{type = result, id = I1}),
|
#iq{type = result, id = I1}),
|
||||||
%% Get subscriptions
|
%% Get subscriptions
|
||||||
true = lists:member(?PUBSUB("retrieve-subscriptions"), Features),
|
true = lists:member(?PUBSUB("retrieve-subscriptions"), Features),
|
||||||
@ -860,8 +860,7 @@ pubsub(Config) ->
|
|||||||
#message{sub_els = [#pubsub_event{
|
#message{sub_els = [#pubsub_event{
|
||||||
items = [#pubsub_event_items{
|
items = [#pubsub_event_items{
|
||||||
node = Node,
|
node = Node,
|
||||||
retract = [ItemID]}]},
|
retract = [ItemID]}]}]}),
|
||||||
#shim{headers = [{<<"Collection">>, Node}]}]}),
|
|
||||||
%% Unsubscribe from node "presence"
|
%% Unsubscribe from node "presence"
|
||||||
#iq{type = result, sub_els = []} =
|
#iq{type = result, sub_els = []} =
|
||||||
send_recv(Config,
|
send_recv(Config,
|
||||||
|
@ -94,7 +94,8 @@
|
|||||||
{mod_offline, [{db_type, odbc}]},
|
{mod_offline, [{db_type, odbc}]},
|
||||||
{mod_privacy, [{db_type, odbc}]},
|
{mod_privacy, [{db_type, odbc}]},
|
||||||
{mod_private, [{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},
|
{ignore_pep_from_offline, true},
|
||||||
{last_item_cache, false},
|
{last_item_cache, false},
|
||||||
{plugins, ["flat", "hometree", "pep"]}]},
|
{plugins, ["flat", "hometree", "pep"]}]},
|
||||||
@ -114,7 +115,8 @@
|
|||||||
{mod_offline, [{db_type, odbc}]},
|
{mod_offline, [{db_type, odbc}]},
|
||||||
{mod_privacy, [{db_type, odbc}]},
|
{mod_privacy, [{db_type, odbc}]},
|
||||||
{mod_private, [{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},
|
{ignore_pep_from_offline, true},
|
||||||
{last_item_cache, false},
|
{last_item_cache, false},
|
||||||
{plugins, ["flat", "hometree", "pep"]}]},
|
{plugins, ["flat", "hometree", "pep"]}]},
|
||||||
@ -133,7 +135,8 @@
|
|||||||
{mod_offline, [{db_type, odbc}]},
|
{mod_offline, [{db_type, odbc}]},
|
||||||
{mod_privacy, [{db_type, odbc}]},
|
{mod_privacy, [{db_type, odbc}]},
|
||||||
{mod_private, [{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},
|
{ignore_pep_from_offline, true},
|
||||||
{last_item_cache, false},
|
{last_item_cache, false},
|
||||||
{plugins, ["flat", "hometree", "pep"]}]},
|
{plugins, ["flat", "hometree", "pep"]}]},
|
||||||
|
@ -26,7 +26,8 @@ host_config:
|
|||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_private:
|
mod_private:
|
||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_pubsub_odbc:
|
mod_pubsub:
|
||||||
|
db_type: odbc
|
||||||
access_createnode: pubsub_createnode
|
access_createnode: pubsub_createnode
|
||||||
ignore_pep_from_offline: true
|
ignore_pep_from_offline: true
|
||||||
last_item_cache: false
|
last_item_cache: false
|
||||||
@ -76,7 +77,8 @@ Welcome to this XMPP server."
|
|||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_private:
|
mod_private:
|
||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_pubsub_odbc:
|
mod_pubsub:
|
||||||
|
db_type: odbc
|
||||||
access_createnode: pubsub_createnode
|
access_createnode: pubsub_createnode
|
||||||
ignore_pep_from_offline: true
|
ignore_pep_from_offline: true
|
||||||
last_item_cache: false
|
last_item_cache: false
|
||||||
@ -132,7 +134,8 @@ Welcome to this XMPP server."
|
|||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_private:
|
mod_private:
|
||||||
db_type: odbc
|
db_type: odbc
|
||||||
mod_pubsub_odbc:
|
mod_pubsub:
|
||||||
|
db_type: odbc
|
||||||
access_createnode: pubsub_createnode
|
access_createnode: pubsub_createnode
|
||||||
ignore_pep_from_offline: true
|
ignore_pep_from_offline: true
|
||||||
last_item_cache: false
|
last_item_cache: false
|
||||||
|
Loading…
Reference in New Issue
Block a user