Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Romain <christophe.romain@process-one.net>2015-04-08 18:12:05 +0300
committerChristophe Romain <christophe.romain@process-one.net>2015-04-21 16:24:16 +0300
commite0563e3918984d151fbea45a5f6fc8255913726d (patch)
treee62bcc5cc538a722f81c3f53291e02594e576711 /src/node_hometree.erl
parent63926efd204c093b3125f789d5114e85ae4ff988 (diff)
PubSub improvements
This commit contains - code cleanup - use of db_type instead of old mod_pubsub_odbc - some minor optimizations - some minor bugfixes
Diffstat (limited to 'src/node_hometree.erl')
-rw-r--r--src/node_hometree.erl1508
1 files changed, 515 insertions, 993 deletions
diff --git a/src/node_hometree.erl b/src/node_hometree.erl
index 6f3c4de74..2840c1850 100644
--- a/src/node_hometree.erl
+++ b/src/node_hometree.erl
@@ -4,20 +4,19 @@
%%% 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/]
@@ -41,122 +40,89 @@
%%% improvements.</p>
-module(node_hometree).
-
+-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net').
-include("pubsub.hrl").
-
-include("jlib.hrl").
--behaviour(gen_pubsub_node).
-
-%% API definition
-export([init/3, terminate/2, options/0, features/0,
- create_node_permission/6, create_node/2, delete_node/1,
- purge_node/2, subscribe_node/8, unsubscribe_node/4,
- publish_item/6, delete_item/4, remove_extra_items/3,
- get_entity_affiliations/2, get_node_affiliations/1,
- get_affiliation/2, set_affiliation/3,
- get_entity_subscriptions/2, get_node_subscriptions/1,
- get_subscriptions/2, set_subscriptions/4,
- get_pending_nodes/2, get_states/1, get_state/2,
- set_state/1, get_items/6, get_items/2, get_item/7,
- get_item/2, set_item/1, get_item_name/3, node_to_path/1,
- path_to_node/1]).
-
-%% ================
-%% 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) ->
+ 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_items/7, get_items/3, get_item/7,
+ get_item/2, set_item/1, get_item_name/3, node_to_path/1,
+ path_to_node/1]).
+
+init(Host, ServerHost, _Opts) ->
pubsub_subscription:init(),
mnesia:create_table(pubsub_state,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, 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)}]),
+ [{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)
+ ItemsFields -> ok;
+ _ -> mnesia:transform_table(pubsub_item, ignore, ItemsFields)
end,
+ Owner = mod_pubsub:service_jid(Host),
+ mod_pubsub:create_node(Host, ServerHost, <<"/home">>, Owner, <<"hometree">>),
+ mod_pubsub:create_node(Host, ServerHost, <<"/home/", ServerHost/binary>>, Owner, <<"hometree">>),
ok.
-%% @spec (Host, ServerHost) -> ok
-%% Host = string()
-%% ServerHost = string()
-%% @doc <p>Called during pubsub modules termination. Any pubsub plugin must
-%% implement this function. It can return anything.</p>
-terminate(_Host, _ServerHost) -> ok.
-
--spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
+terminate(_Host, _ServerHost) ->
+ ok.
-%% @spec () -> Options
-%% Options = [mod_pubsub:nodeOption()]
-%% @doc Returns the default pubsub node options.
-%% <p>Example of function return value:</p>
-%% ```
-%% [{deliver_payloads, true},
-%% {notify_config, false},
-%% {notify_delete, false},
-%% {notify_retract, true},
-%% {persist_items, true},
-%% {max_items, 10},
-%% {subscribe, true},
-%% {access_model, open},
-%% {publish_model, publishers},
-%% {max_payload_size, 100000},
-%% {send_last_published_item, never},
-%% {presence_based_delivery, false}]'''
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}].
+ [{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}].
-%% @spec () -> Features
-%% Features = [string()]
-%% @doc Returns the node features
--spec(features/0 :: () -> Features::[binary(),...]).
features() ->
- [<<"create-nodes">>, <<"auto-create">>,
- <<"access-authorize">>, <<"delete-nodes">>,
- <<"delete-items">>, <<"get-pending">>,
- <<"instant-nodes">>, <<"manage-subscriptions">>,
- <<"modify-affiliations">>, <<"multi-subscribe">>,
- <<"outcast-affiliation">>, <<"persistent-items">>,
- <<"publish">>, <<"purge-nodes">>, <<"retract-items">>,
- <<"retrieve-affiliations">>, <<"retrieve-items">>,
- <<"retrieve-subscriptions">>, <<"subscribe">>,
- <<"subscription-notifications">>,
- <<"subscription-options">>].
+ [<<"create-nodes">>,
+ <<"auto-create">>,
+ <<"access-authorize">>,
+ <<"delete-nodes">>,
+ <<"delete-items">>,
+ <<"get-pending">>,
+ <<"instant-nodes">>,
+ <<"manage-subscriptions">>,
+ <<"modify-affiliations">>,
+ <<"multi-subscribe">>,
+ <<"outcast-affiliation">>,
+ <<"persistent-items">>,
+ <<"publish">>,
+ <<"purge-nodes">>,
+ <<"retract-items">>,
+ <<"retrieve-affiliations">>,
+ <<"retrieve-items">>,
+ <<"retrieve-subscriptions">>,
+ <<"subscribe">>,
+ <<"subscription-notifications">>,
+ <<"subscription-options">>].
-%% @spec (Host, ServerHost, NodeId, ParentNodeId, Owner, Access) -> {result, Allowed}
-%% Host = mod_pubsub:hostPubsub()
-%% ServerHost = string()
-%% NodeId = mod_pubsub:nodeId()
-%% ParentNodeId = mod_pubsub:nodeId()
-%% Owner = mod_pubsub:jid()
-%% Access = all | atom()
-%% Allowed = boolean()
%% @doc Checks if the current user has the permission to create the requested node
%% <p>In {@link node_default}, the permission is decided by the place in the
%% hierarchy where the user is creating the node. The access parameter is also
@@ -164,99 +130,44 @@ features() ->
%% <tt>access_createnode</tt> ACL value in ejabberd config file.</p>
%% <p>This function also check that node can be created a a children of its
%% parent node</p>
-%% <p>PubSub plugins can redefine the PubSub node creation rights as they
-%% which. They can simply delegate this check to the {@link node_default}
-%% module by implementing this function like this:
-%% ```check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access) ->
-%% node_default:check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access).'''</p>
--spec(create_node_permission/6 ::
-(
- Host :: mod_pubsub:host(),
- ServerHost :: binary(),
- NodeId :: mod_pubsub:nodeId(),
- _ParentNodeId :: mod_pubsub:nodeId(),
- Owner :: jid(),
- Access :: atom())
- -> {result, boolean()}
-).
-
-create_node_permission(Host, ServerHost, NodeId, _ParentNodeId, Owner, Access) ->
+create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
LOwner = jlib:jid_tolower(Owner),
{User, Server, _Resource} = LOwner,
Allowed = case LOwner of
- {<<"">>, Host, <<"">>} ->
- true; % pubsub service always allowed
- _ ->
- case acl:match_rule(ServerHost, Access, LOwner) of
- allow ->
- case node_to_path(NodeId) of
- [<<"home">>, Server, User | _] -> true;
- _ -> false
- end;
- _ -> false
- end
- end,
+ {<<"">>, Host, <<"">>} ->
+ true; % pubsub service always allowed
+ _ ->
+ case acl:match_rule(ServerHost, Access, LOwner) of
+ allow ->
+ case node_to_path(Node) of
+ [<<"home">>, Server, User | _] -> true;
+ _ -> false
+ end;
+ _ -> false
+ end
+ end,
{result, Allowed}.
-%% @spec (NodeIdx, Owner) -> {result, {default, broadcast}}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Owner = mod_pubsub:jid()
-%% @doc <p></p>
--spec(create_node/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: jid())
- -> {result, {default, broadcast}}
-).
-
-create_node(NodeIdx, Owner) ->
+create_node(Nidx, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- set_state(#pubsub_state{stateid = {OwnerKey, NodeIdx}, affiliation = owner}),
+ set_state(#pubsub_state{stateid = {OwnerKey, Nidx},
+ affiliation = owner}),
{result, {default, broadcast}}.
-%% @spec (Nodes) -> {result, {default, broadcast, Reply}}
-%% Nodes = [mod_pubsub:pubsubNode()]
-%% Reply = [{mod_pubsub:pubsubNode(),
-%% [{mod_pubsub:ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]}]}]
-%% @doc <p>purge items of deleted nodes after effective deletion.</p>
--spec(delete_node/1 ::
-(
- Nodes :: [mod_pubsub:pubsubNode(),...])
- -> {result,
- {default, broadcast,
- [{mod_pubsub:pubsubNode(),
- [{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]},...]},...]
- }
- }
-).
delete_node(Nodes) ->
Tr = fun (#pubsub_state{stateid = {J, _}, subscriptions = Ss}) ->
- lists:map(fun (S) -> {J, S} end, Ss)
- end,
- Reply = lists:map(fun (#pubsub_node{id = NodeIdx} = PubsubNode) ->
- {result, States} = get_states(NodeIdx),
- lists:foreach(fun (#pubsub_state{stateid = {LJID, _}, items = Items}) ->
- del_items(NodeIdx, Items),
- del_state(NodeIdx, LJID)
- end, States),
- {PubsubNode, lists:flatmap(Tr, States)}
- end, Nodes),
+ lists:map(fun (S) -> {J, S} end, Ss)
+ end,
+ Reply = lists:map(fun (#pubsub_node{id = Nidx} = PubsubNode) ->
+ {result, States} = get_states(Nidx),
+ lists:foreach(fun (#pubsub_state{stateid = {LJID, _}, items = Items}) ->
+ del_items(Nidx, Items),
+ del_state(Nidx, LJID)
+ end, States),
+ {PubsubNode, lists:flatmap(Tr, States)}
+ end, Nodes),
{result, {default, broadcast, Reply}}.
-%% @spec (NodeIdx, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> {error, Reason} | {result, Result}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Sender = mod_pubsub:jid()
-%% Subscriber = mod_pubsub:jid()
-%% AccessModel = mod_pubsub:accessModel()
-%% SendLast = atom()
-%% PresenceSubscription = boolean()
-%% RosterGroup = boolean()
-%% Options = [mod_pubsub:nodeOption()]
-%% Reason = mod_pubsub:stanzaError()
-%% Result = {result, {default, subscribed, mod_pubsub:subId()}}
-%% | {result, {default, subscribed, mod_pubsub:subId(), send_last}}
-%% | {result, {default, pending, mod_pubsub:subId()}}
-%%
%% @doc <p>Accepts or rejects subcription requests on a PubSub node.</p>
%% <p>The mechanism works as follow:
%% <ul>
@@ -288,199 +199,138 @@ delete_node(Nodes) ->
%% to completly disable persistance.</li></ul>
%% </p>
%% <p>In the default plugin module, the record is unchanged.</p>
--spec(subscribe_node/8 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Sender :: jid(),
- Subscriber :: ljid(),
- AccessModel :: mod_pubsub:accessModel(),
- SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
- PresenceSubscription :: boolean(),
- RosterGroup :: boolean(),
- Options :: mod_pubsub:subOptions())
- -> {result, {default, subscribed, mod_pubsub:subId()}}
- | {result, {default, subscribed, mod_pubsub:subId(), send_last}}
- | {result, {default, pending, mod_pubsub:subId()}}
- %%%
- | {error, xmlel()}
-).
-subscribe_node(NodeIdx, Sender, Subscriber, AccessModel,
- SendLast, PresenceSubscription, RosterGroup, Options) ->
+subscribe_node(Nidx, Sender, Subscriber, AccessModel,
+ SendLast, PresenceSubscription, RosterGroup, Options) ->
SubKey = jlib:jid_tolower(Subscriber),
GenKey = jlib:jid_remove_resource(SubKey),
- Authorized =
- jlib:jid_tolower(jlib:jid_remove_resource(Sender)) ==
- GenKey,
- GenState = get_state(NodeIdx, GenKey),
+ Authorized = jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey,
+ GenState = get_state(Nidx, GenKey),
SubState = case SubKey of
- GenKey -> GenState;
- _ -> get_state(NodeIdx, SubKey)
- end,
+ GenKey -> GenState;
+ _ -> get_state(Nidx, SubKey)
+ end,
Affiliation = GenState#pubsub_state.affiliation,
Subscriptions = SubState#pubsub_state.subscriptions,
- Whitelisted = lists:member(Affiliation,
- [member, publisher, owner]),
- PendingSubscription = lists:any(fun ({pending, _}) ->
- true;
- (_) -> false
- end,
- Subscriptions),
+ Whitelisted = lists:member(Affiliation, [member, publisher, owner]),
+ PendingSubscription = lists:any(fun
+ ({pending, _}) -> true;
+ (_) -> false
+ end,
+ Subscriptions),
if not Authorized ->
- {error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)};
- Affiliation == outcast -> {error, ?ERR_FORBIDDEN};
- PendingSubscription ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"pending-subscription">>)};
- (AccessModel == presence) and
- not PresenceSubscription ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"presence-subscription-required">>)};
- (AccessModel == roster) and not RosterGroup ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"not-in-roster-group">>)};
- (AccessModel == whitelist) and not Whitelisted ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
- %%MustPay ->
- %% % Payment is required for a subscription
- %% {error, ?ERR_PAYMENT_REQUIRED};
- %%ForbiddenAnonymous ->
- %% % Requesting entity is anonymous
- %% {error, ?ERR_FORBIDDEN};
- true ->
- SubId = pubsub_subscription:add_subscription(Subscriber, NodeIdx, Options),
- NewSub = case AccessModel of
- authorize -> pending;
- _ -> subscribed
- end,
- set_state(SubState#pubsub_state{subscriptions =
- [{NewSub, SubId} | Subscriptions]}),
- case {NewSub, SendLast} of
- {subscribed, never} ->
- {result, {default, subscribed, SubId}};
- {subscribed, _} ->
- {result, {default, subscribed, SubId, send_last}};
- {_, _} -> {result, {default, pending, SubId}}
- end
+ {error,
+ ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)};
+ Affiliation == outcast ->
+ {error, ?ERR_FORBIDDEN};
+ PendingSubscription ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"pending-subscription">>)};
+ (AccessModel == presence) and not PresenceSubscription ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ (AccessModel == roster) and not RosterGroup ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ (AccessModel == whitelist) and not Whitelisted ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ %%MustPay ->
+ %% % Payment is required for a subscription
+ %% {error, ?ERR_PAYMENT_REQUIRED};
+ %%ForbiddenAnonymous ->
+ %% % Requesting entity is anonymous
+ %% {error, ?ERR_FORBIDDEN};
+ true ->
+ SubId = pubsub_subscription:add_subscription(Subscriber, Nidx, Options),
+ NewSub = case AccessModel of
+ authorize -> pending;
+ _ -> subscribed
+ end,
+ set_state(SubState#pubsub_state{subscriptions =
+ [{NewSub, SubId} | Subscriptions]}),
+ case {NewSub, SendLast} of
+ {subscribed, never} ->
+ {result, {default, subscribed, SubId}};
+ {subscribed, _} ->
+ {result, {default, subscribed, SubId, send_last}};
+ {_, _} ->
+ {result, {default, pending, SubId}}
+ end
end.
-%% @spec (NodeIdx, Sender, Subscriber, SubId) -> {error, Reason} | {result, default}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Sender = mod_pubsub:jid()
-%% Subscriber = mod_pubsub:jid()
-%% SubId = mod_pubsub:subId()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
--spec(unsubscribe_node/4 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Sender :: jid(),
- Subscriber :: ljid(),
- SubId :: subId())
- -> {result, default}
- %
- | {error, xmlel()}
-).
-
-unsubscribe_node(NodeIdx, Sender, Subscriber, SubId) ->
+unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
SubKey = jlib:jid_tolower(Subscriber),
GenKey = jlib:jid_remove_resource(SubKey),
- Authorized =
- jlib:jid_tolower(jlib:jid_remove_resource(Sender)) ==
- GenKey,
- GenState = get_state(NodeIdx, GenKey),
+ Authorized = jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey,
+ GenState = get_state(Nidx, GenKey),
SubState = case SubKey of
- GenKey -> GenState;
- _ -> get_state(NodeIdx, SubKey)
- end,
- Subscriptions = lists:filter(fun ({_Sub, _SubId}) ->
- true;
- (_SubId) -> false
- end,
- SubState#pubsub_state.subscriptions),
+ GenKey -> GenState;
+ _ -> get_state(Nidx, SubKey)
+ end,
+ Subscriptions = lists:filter(fun
+ ({_Sub, _SubId}) -> true;
+ (_SubId) -> false
+ end,
+ SubState#pubsub_state.subscriptions),
SubIdExists = case SubId of
- <<>> -> false;
- Binary when is_binary(Binary) -> true;
- _ -> false
- end,
+ <<>> -> false;
+ Binary when is_binary(Binary) -> true;
+ _ -> false
+ end,
if
- %% Requesting entity is prohibited from unsubscribing entity
- not Authorized -> {error, ?ERR_FORBIDDEN};
- %% Entity did not specify SubId
- %%SubId == "", ?? ->
- %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
- %% Invalid subscription identifier
- %%InvalidSubId ->
- %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
- %% Requesting entity is not a subscriber
- Subscriptions == [] ->
- {error,
- ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL),
- <<"not-subscribed">>)};
- %% Subid supplied, so use that.
- SubIdExists ->
- Sub = first_in_list(fun (S) ->
- case S of
- {_Sub, SubId} -> true;
- _ -> false
- end
- end,
- SubState#pubsub_state.subscriptions),
- case Sub of
- {value, S} ->
- delete_subscriptions(SubKey, NodeIdx, [S], SubState),
- {result, default};
- false ->
- {error,
- ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL),
- <<"not-subscribed">>)}
- end;
- %% Asking to remove all subscriptions to the given node
- SubId == all ->
- delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
- {result, default};
- %% No subid supplied, but there's only one matching subscription
- length(Subscriptions) == 1 ->
- delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
- {result, default};
- %% No subid and more than one possible subscription match.
- true ->
- {error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}
+ %% Requesting entity is prohibited from unsubscribing entity
+ not Authorized ->
+ {error, ?ERR_FORBIDDEN};
+ %% Entity did not specify SubId
+ %%SubId == "", ?? ->
+ %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %% Invalid subscription identifier
+ %%InvalidSubId ->
+ %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ %% Requesting entity is not a subscriber
+ Subscriptions == [] ->
+ {error,
+ ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)};
+ %% Subid supplied, so use that.
+ SubIdExists ->
+ Sub = first_in_list(fun
+ ({_, S}) when S == SubId -> true;
+ (_) -> false
+ end,
+ SubState#pubsub_state.subscriptions),
+ case Sub of
+ {value, S} ->
+ delete_subscriptions(SubKey, Nidx, [S], SubState),
+ {result, default};
+ false ->
+ {error,
+ ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)}
+ end;
+ %% Asking to remove all subscriptions to the given node
+ SubId == all ->
+ delete_subscriptions(SubKey, Nidx, Subscriptions, SubState),
+ {result, default};
+ %% No subid supplied, but there's only one matching subscription
+ length(Subscriptions) == 1 ->
+ delete_subscriptions(SubKey, Nidx, Subscriptions, SubState),
+ {result, default};
+ %% No subid and more than one possible subscription match.
+ true ->
+ {error,
+ ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}
end.
--spec(delete_subscriptions/4 ::
-(
- SubKey :: ljid(),
- NodeIdx :: mod_pubsub:nodeIdx(),
- Subscriptions :: [{mod_pubsub:subscription(), mod_pubsub:subId()}],
- SubState :: mod_pubsub:pubsubState())
- -> ok
-).
-delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState) ->
+delete_subscriptions(SubKey, Nidx, Subscriptions, SubState) ->
NewSubs = lists:foldl(fun ({Subscription, SubId}, Acc) ->
- pubsub_subscription:delete_subscription(SubKey, NodeIdx, SubId),
- Acc -- [{Subscription, SubId}]
- end, SubState#pubsub_state.subscriptions, Subscriptions),
+ pubsub_subscription:delete_subscription(SubKey, Nidx, SubId),
+ Acc -- [{Subscription, SubId}]
+ end, SubState#pubsub_state.subscriptions, Subscriptions),
case {SubState#pubsub_state.affiliation, NewSubs} of
- {none, []} -> del_state(NodeIdx, SubKey);
- _ -> set_state(SubState#pubsub_state{subscriptions = NewSubs})
+ {none, []} -> del_state(Nidx, SubKey);
+ _ -> set_state(SubState#pubsub_state{subscriptions = NewSubs})
end.
-%% @spec (NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
-%% {result, {default, broadcast, ItemIds}} | {error, Reason}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Publisher = mod_pubsub:jid()
-%% PublishModel = atom()
-%% MaxItems = integer()
-%% ItemId = mod_pubsub:itemId()
-%% Payload = mod_pubsub:payload()
-%% ItemIds = [mod_pubsub:itemId()] | []
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Publishes the item passed as parameter.</p>
%% <p>The mechanism works as follow:
%% <ul>
@@ -511,70 +361,48 @@ delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState) ->
%% to completly disable persistance.</li></ul>
%% </p>
%% <p>In the default plugin module, the record is unchanged.</p>
--spec(publish_item/6 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Publisher :: jid(),
- PublishModel :: mod_pubsub:publishModel(),
- Max_Items :: non_neg_integer(),
- ItemId :: <<>> | mod_pubsub:itemId(),
- Payload :: mod_pubsub:payload())
- -> {result, {default, broadcast, [mod_pubsub:itemId()]}}
- %%%
- | {error, xmlel()}
-).
-
-publish_item(NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
+publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
SubKey = jlib:jid_tolower(Publisher),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
+ GenState = get_state(Nidx, GenKey),
SubState = case SubKey of
- GenKey -> GenState;
- _ -> get_state(NodeIdx, SubKey)
- end,
+ GenKey -> GenState;
+ _ -> get_state(Nidx, SubKey)
+ end,
Affiliation = GenState#pubsub_state.affiliation,
Subscribed = case PublishModel of
- subscribers ->
- is_subscribed(SubState#pubsub_state.subscriptions);
- _ -> undefined
- end,
- if not
- ((PublishModel == open) or
- (PublishModel == publishers) and
- ((Affiliation == owner) or (Affiliation == publisher))
- or (Subscribed == true)) ->
- {error, ?ERR_FORBIDDEN};
- true ->
- if MaxItems > 0 ->
- Now = now(),
- PubId = {Now, SubKey},
- Item = case get_item(NodeIdx, ItemId) of
- {result, OldItem} ->
- OldItem#pubsub_item{modification = PubId,
- payload = Payload};
- _ ->
- #pubsub_item{itemid = {ItemId, NodeIdx},
- creation = {Now, GenKey},
- modification = PubId,
- payload = Payload}
- end,
- Items = [ItemId | GenState#pubsub_state.items --
- [ItemId]],
- {result, {NI, OI}} = remove_extra_items(NodeIdx,
- MaxItems, Items),
- set_item(Item),
- set_state(GenState#pubsub_state{items = NI}),
- {result, {default, broadcast, OI}};
- true -> {result, {default, broadcast, []}}
- end
+ subscribers -> is_subscribed(SubState#pubsub_state.subscriptions);
+ _ -> undefined
+ end,
+ if not ((PublishModel == open) or
+ (PublishModel == publishers) and
+ ((Affiliation == owner) or (Affiliation == publisher))
+ or (Subscribed == true)) ->
+ {error, ?ERR_FORBIDDEN};
+ true ->
+ if MaxItems > 0 ->
+ Now = now(),
+ PubId = {Now, SubKey},
+ Item = case get_item(Nidx, ItemId) of
+ {result, OldItem} ->
+ OldItem#pubsub_item{modification = PubId,
+ payload = Payload};
+ _ ->
+ #pubsub_item{itemid = {ItemId, Nidx},
+ creation = {Now, GenKey},
+ modification = PubId,
+ payload = Payload}
+ end,
+ Items = [ItemId | GenState#pubsub_state.items -- [ItemId]],
+ {result, {NI, OI}} = remove_extra_items(Nidx, MaxItems, Items),
+ set_item(Item),
+ set_state(GenState#pubsub_state{items = NI}),
+ {result, {default, broadcast, OI}};
+ true ->
+ {result, {default, broadcast, []}}
+ end
end.
-%% @spec (NodeIdx, MaxItems, ItemIds) -> {result, {NewItemIds,OldItemIds}}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% MaxItems = integer() | unlimited
-%% ItemIds = [mod_pubsub:itemId()]
-%% NewItemIds = [mod_pubsub:itemId()]
-%% OldItemIds = [mod_pubsub:itemId()] | []
%% @doc <p>This function is used to remove extra items, most notably when the
%% maximum number of items has been reached.</p>
%% <p>This function is used internally by the core PubSub module, as no
@@ -583,119 +411,84 @@ publish_item(NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
%% rules can be used.</p>
%% <p>If another PubSub plugin wants to delegate the item removal (and if the
%% plugin is using the default pubsub storage), it can implements this function like this:
-%% ```remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
-%% node_default:remove_extra_items(NodeIdx, MaxItems, ItemIds).'''</p>
--spec(remove_extra_items/3 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Max_Items :: unlimited | non_neg_integer(),
- ItemIds :: [mod_pubsub:itemId()])
- -> {result,
- {NewItems::[mod_pubsub:itemId()],
- OldItems::[mod_pubsub:itemId()]}
- }
-).
-remove_extra_items(_NodeIdx, unlimited, ItemIds) ->
+%% ```remove_extra_items(Nidx, MaxItems, ItemIds) ->
+%% node_default:remove_extra_items(Nidx, MaxItems, ItemIds).'''</p>
+remove_extra_items(_Nidx, unlimited, ItemIds) ->
{result, {ItemIds, []}};
-remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
+remove_extra_items(Nidx, MaxItems, ItemIds) ->
NewItems = lists:sublist(ItemIds, MaxItems),
OldItems = lists:nthtail(length(NewItems), ItemIds),
- del_items(NodeIdx, OldItems),
+ del_items(Nidx, OldItems),
{result, {NewItems, OldItems}}.
-%% @spec (NodeIdx, Publisher, PublishModel, ItemId) ->
-%% {result, {default, broadcast}} | {error, Reason}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Publisher = mod_pubsub:jid()
-%% PublishModel = atom()
-%% ItemId = mod_pubsub:itemId()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Triggers item deletion.</p>
%% <p>Default plugin: The user performing the deletion must be the node owner
%% or a publisher, or PublishModel being open.</p>
--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) ->
+delete_item(Nidx, Publisher, PublishModel, ItemId) ->
SubKey = jlib:jid_tolower(Publisher),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
+ GenState = get_state(Nidx, GenKey),
#pubsub_state{affiliation = Affiliation, items = Items} = GenState,
Allowed = Affiliation == publisher orelse
- Affiliation == owner orelse
- PublishModel == open orelse
- case get_item(NodeIdx, ItemId) of
- {result, #pubsub_item{creation = {_, GenKey}}} -> true;
- _ -> false
- end,
- if not Allowed -> {error, ?ERR_FORBIDDEN};
- true ->
- case lists:member(ItemId, Items) of
- true ->
- del_item(NodeIdx, ItemId),
- set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}),
- {result, {default, broadcast}};
- false ->
- case Affiliation of
- owner ->
- {result, States} = get_states(NodeIdx),
- lists:foldl(fun (#pubsub_state{items = PI} = S, Res) ->
- case lists:member(ItemId, PI) of
- true ->
- del_item(NodeIdx, ItemId),
- set_state(S#pubsub_state{items
- = lists:delete(ItemId, PI)}),
- {result, {default, broadcast}};
- false -> Res
- end;
- (_, Res) -> Res
- end,
- {error, ?ERR_ITEM_NOT_FOUND}, States);
- _ -> {error, ?ERR_ITEM_NOT_FOUND}
- end
- end
+ Affiliation == owner orelse
+ PublishModel == open orelse
+ case get_item(Nidx, ItemId) of
+ {result, #pubsub_item{creation = {_, GenKey}}} -> true;
+ _ -> false
+ end,
+ if not Allowed ->
+ {error, ?ERR_FORBIDDEN};
+ true ->
+ case lists:member(ItemId, Items) of
+ true ->
+ del_item(Nidx, ItemId),
+ set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}),
+ {result, {default, broadcast}};
+ false ->
+ case Affiliation of
+ owner ->
+ {result, States} = get_states(Nidx),
+ lists:foldl(fun
+ (#pubsub_state{items = PI} = S, Res) ->
+ case lists:member(ItemId, PI) of
+ true ->
+ Nitems = lists:delete(ItemId, PI),
+ del_item(Nidx, ItemId),
+ set_state(S#pubsub_state{items = Nitems}),
+ {result, {default, broadcast}};
+ false ->
+ Res
+ end;
+ (_, Res) ->
+ Res
+ end,
+ {error, ?ERR_ITEM_NOT_FOUND}, States);
+ _ ->
+ {error, ?ERR_ITEM_NOT_FOUND}
+ end
+ end
end.
-%% @spec (NodeIdx, Owner) -> {error, Reason} | {result, {default, broadcast}}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% Owner = mod_pubsub:jid()
-%% Reason = mod_pubsub:stanzaError()
--spec(purge_node/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: jid())
- -> {result, {default, broadcast}}
- | {error, xmlel()}
-).
-
-purge_node(NodeIdx, Owner) ->
+purge_node(Nidx, Owner) ->
SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
+ GenState = get_state(Nidx, GenKey),
case GenState of
- #pubsub_state{affiliation = owner} ->
- {result, States} = get_states(NodeIdx),
- lists:foreach(fun (#pubsub_state{items = []}) -> ok;
- (#pubsub_state{items = Items} = S) ->
- del_items(NodeIdx, Items),
- set_state(S#pubsub_state{items = []})
- end,
- States),
- {result, {default, broadcast}};
- _ -> {error, ?ERR_FORBIDDEN}
+ #pubsub_state{affiliation = owner} ->
+ {result, States} = get_states(Nidx),
+ lists:foreach(fun
+ (#pubsub_state{items = []}) ->
+ ok;
+ (#pubsub_state{items = Items} = S) ->
+ del_items(Nidx, Items),
+ set_state(S#pubsub_state{items = []})
+ end,
+ States),
+ {result, {default, broadcast}};
+ _ ->
+ {error, ?ERR_FORBIDDEN}
end.
-%% @spec (Host, Owner) -> {result, Reply}
-%% Host = mod_pubsub:hostPubsub()
-%% Owner = mod_pubsub:jid()
-%% Reply = [] | [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]
%% @doc <p>Return the current affiliations for the given user</p>
%% <p>The default module reads affiliations in the main Mnesia
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
@@ -703,88 +496,40 @@ purge_node(NodeIdx, Owner) ->
%% the default PubSub module. Otherwise, it should return its own affiliation,
%% that will be added to the affiliation stored in the main
%% <tt>pubsub_state</tt> table.</p>
--spec(get_entity_affiliations/2 ::
-(
- Host :: mod_pubsub:host(),
- Owner :: jid())
- -> {result, [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]}
-).
-
get_entity_affiliations(Host, Owner) ->
SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey),
States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
- NodeTree = case catch
- ets:lookup(gen_mod:get_module_proc(Host, config),
- nodetree)
- of
- [{nodetree, N}] -> N;
- _ -> nodetree_tree
- end,
- Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A},
- Acc) ->
- case NodeTree:get_node(N) of
- #pubsub_node{nodeid = {Host, _}} = Node ->
- [{Node, A} | Acc];
- _ -> Acc
- end
- end,
- [], States),
+ NodeTree = mod_pubsub:tree(Host),
+ Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) ->
+ case NodeTree:get_node(N) of
+ #pubsub_node{nodeid = {Host, _}} = Node -> [{Node, A} | Acc];
+ _ -> Acc
+ end
+ end,
+ [], States),
{result, Reply}.
--spec(get_node_affiliations/1 ::
-(
- NodeIdx::mod_pubsub:nodeIdx())
- -> {result, [{ljid(), mod_pubsub:affiliation()}]}
-).
-
-get_node_affiliations(NodeIdx) ->
- {result, States} = get_states(NodeIdx),
- Tr = fun (#pubsub_state{stateid = {J, _},
- affiliation = A}) ->
- {J, A}
- end,
+get_node_affiliations(Nidx) ->
+ {result, States} = get_states(Nidx),
+ Tr = fun (#pubsub_state{stateid = {J, _}, affiliation = A}) -> {J, A} end,
{result, lists:map(Tr, States)}.
--spec(get_affiliation/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: jid())
- -> {result, mod_pubsub:affiliation()}
-).
-
-get_affiliation(NodeIdx, Owner) ->
+get_affiliation(Nidx, Owner) ->
SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey),
- #pubsub_state{affiliation = Affiliation} = get_state(NodeIdx, GenKey),
+ #pubsub_state{affiliation = Affiliation} = get_state(Nidx, GenKey),
{result, Affiliation}.
--spec(set_affiliation/3 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: ljid(),
- Affiliation :: mod_pubsub:affiliation())
- -> ok
-).
-set_affiliation(NodeIdx, Owner, Affiliation) ->
+set_affiliation(Nidx, Owner, Affiliation) ->
SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
+ GenState = get_state(Nidx, GenKey),
case {Affiliation, GenState#pubsub_state.subscriptions} of
- {none, []} -> del_state(NodeIdx, GenKey);
- _ -> set_state(GenState#pubsub_state{affiliation = Affiliation})
+ {none, []} -> del_state(Nidx, GenKey);
+ _ -> set_state(GenState#pubsub_state{affiliation = Affiliation})
end.
-%% @spec (Host, Owner) ->
-%% {'result', []
-%% | [{Node, Subscription, SubId, Entity}]
-%% | [{Node, Subscription, Entity}]}
-%% Host = mod_pubsub:hostPubsub()
-%% Owner = mod_pubsub:jid()
-%% Node = mod_pubsub:pubsubNode()
-%% Subscription = mod_pubsub:subscription()
-%% SubId = mod_pubsub:subId()
-%% Entity = mod_pubsub:ljid()
%% @doc <p>Return the current subscriptions for the given user</p>
%% <p>The default module reads subscriptions in the main Mnesia
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
@@ -792,130 +537,79 @@ set_affiliation(NodeIdx, Owner, Affiliation) ->
%% the default PubSub module. Otherwise, it should return its own affiliation,
%% that will be added to the affiliation stored in the main
%% <tt>pubsub_state</tt> table.</p>
--spec(get_entity_subscriptions/2 ::
-(
- Host :: mod_pubsub:host(),
- 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),
GenKey = jlib:jid_remove_resource(SubKey),
States = case SubKey of
- GenKey ->
- mnesia:match_object(#pubsub_state{stateid =
- {{U, D, '_'}, '_'},
- _ = '_'});
- _ ->
- mnesia:match_object(#pubsub_state{stateid =
- {GenKey, '_'},
- _ = '_'})
- ++
- mnesia:match_object(#pubsub_state{stateid =
- {SubKey, '_'},
- _ = '_'})
- end,
- NodeTree = case catch
- ets:lookup(gen_mod:get_module_proc(Host, config),
- nodetree)
- of
- [{nodetree, N}] -> N;
- _ -> nodetree_tree
- end,
- Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss},
- Acc) ->
- case NodeTree:get_node(N) of
- #pubsub_node{nodeid = {Host, _}} = Node ->
- lists:foldl(fun ({Sub, SubId}, Acc2) ->
- [{Node, Sub, SubId, J} | Acc2]
- end,
- Acc, Ss);
- _ -> Acc
- end
- end,
- [], States),
+ GenKey ->
+ mnesia:match_object(#pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
+ _ ->
+ mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
+ ++
+ mnesia:match_object(#pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
+ end,
+ NodeTree = mod_pubsub:tree(Host),
+ Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) ->
+ case NodeTree:get_node(N) of
+ #pubsub_node{nodeid = {Host, _}} = Node ->
+ lists:foldl(fun ({Sub, SubId}, Acc2) ->
+ [{Node, Sub, SubId, J} | Acc2]
+ end,
+ Acc, Ss);
+ _ ->
+ Acc
+ end
+ end,
+ [], States),
{result, Reply}.
--spec(get_node_subscriptions/1 ::
-(
- NodeIdx::mod_pubsub:nodeIdx())
- -> {result,
- [{ljid(), mod_pubsub:subscription(), mod_pubsub:subId()}] |
- [{ljid(), none},...]
- }
-).
-get_node_subscriptions(NodeIdx) ->
- {result, States} = get_states(NodeIdx),
- Tr = fun (#pubsub_state{stateid = {J, _},
- subscriptions = Subscriptions}) ->
- case Subscriptions of
- [_ | _] ->
- lists:foldl(fun ({S, SubId}, Acc) ->
- [{J, S, SubId} | Acc]
- end,
- [], Subscriptions);
- [] -> [];
- _ -> [{J, none}]
- end
- end,
+get_node_subscriptions(Nidx) ->
+ {result, States} = get_states(Nidx),
+ Tr = fun (#pubsub_state{stateid = {J, _}, subscriptions = Subscriptions}) ->
+ case Subscriptions of
+ [_ | _] ->
+ lists:foldl(fun ({S, SubId}, Acc) ->
+ [{J, S, SubId} | Acc]
+ end,
+ [], Subscriptions);
+ [] ->
+ [];
+ _ ->
+ [{J, none}]
+ end
+ end,
{result, lists:flatmap(Tr, States)}.
--spec(get_subscriptions/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: ljid())
- -> {result, [{mod_pubsub:subscription(), mod_pubsub:subId()}]}
-).
-get_subscriptions(NodeIdx, Owner) ->
+get_subscriptions(Nidx, Owner) ->
SubKey = jlib:jid_tolower(Owner),
- SubState = get_state(NodeIdx, SubKey),
+ SubState = get_state(Nidx, SubKey),
{result, SubState#pubsub_state.subscriptions}.
--spec(set_subscriptions/4 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- Owner :: jid(),
- Subscription :: mod_pubsub:subscription(),
- SubId :: mod_pubsub:subId())
- -> ok
- %%%
- | {error, xmlel()}
-).
-
-set_subscriptions(NodeIdx, Owner, Subscription, SubId) ->
+set_subscriptions(Nidx, Owner, Subscription, SubId) ->
SubKey = jlib:jid_tolower(Owner),
- SubState = get_state(NodeIdx, SubKey),
+ SubState = get_state(Nidx, SubKey),
case {SubId, SubState#pubsub_state.subscriptions} of
- {_, []} ->
- case Subscription of
- none ->
- {error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST),
- <<"not-subscribed">>)};
- _ ->
- new_subscription(NodeIdx, Owner, Subscription, SubState)
- end;
- {<<>>, [{_, SID}]} ->
- case Subscription of
- none -> unsub_with_subid(NodeIdx, SID, SubState);
- _ -> replace_subscription({Subscription, SID}, SubState)
- end;
- {<<>>, [_ | _]} ->
- {error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST),
- <<"subid-required">>)};
- _ ->
- case Subscription of
- none -> unsub_with_subid(NodeIdx, SubId, SubState);
- _ ->
- replace_subscription({Subscription, SubId}, SubState)
- end
+ {_, []} ->
+ case Subscription of
+ none ->
+ {error,
+ ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"not-subscribed">>)};
+ _ ->
+ new_subscription(Nidx, Owner, Subscription, SubState)
+ end;
+ {<<>>, [{_, SID}]} ->
+ case Subscription of
+ none -> unsub_with_subid(Nidx, SID, SubState);
+ _ -> replace_subscription({Subscription, SID}, SubState)
+ end;
+ {<<>>, [_ | _]} ->
+ {error,
+ ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)};
+ _ ->
+ case Subscription of
+ none -> unsub_with_subid(Nidx, SubId, SubState);
+ _ -> replace_subscription({Subscription, SubId}, SubState)
+ end
end.
replace_subscription(NewSub, SubState) ->
@@ -923,103 +617,64 @@ replace_subscription(NewSub, SubState) ->
set_state(SubState#pubsub_state{subscriptions = NewSubs}).
replace_subscription(_, [], Acc) -> Acc;
-replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) ->
- replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]).
-
-new_subscription(NodeId, Owner, Subscription, SubState) ->
- SubId = pubsub_subscription:add_subscription(Owner, NodeId, []),
- Subscriptions = SubState#pubsub_state.subscriptions,
- set_state(SubState#pubsub_state{subscriptions =
- [{Subscription, SubId} | Subscriptions]}),
- {Subscription, SubId}.
-
--spec(unsub_with_subid/3 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- SubId :: mod_pubsub:subId(),
- SubState :: mod_pubsub:pubsubState())
- -> ok
-).
-unsub_with_subid(NodeIdx, SubId, #pubsub_state{stateid = {Entity, _}} = SubState) ->
- pubsub_subscription:delete_subscription(SubState#pubsub_state.stateid,
- NodeIdx, SubId),
- NewSubs = lists:filter(fun ({_, SID}) -> SubId =/= SID
- end,
- SubState#pubsub_state.subscriptions),
+replace_subscription({Sub, SubId}, [{_, SubId} | T], Acc) ->
+ replace_subscription({Sub, SubId}, T, [{Sub, SubId} | Acc]).
+
+new_subscription(Nidx, Owner, Sub, SubState) ->
+ SubId = pubsub_subscription:add_subscription(Owner, Nidx, []),
+ Subs = SubState#pubsub_state.subscriptions,
+ set_state(SubState#pubsub_state{subscriptions = [{Sub, SubId} | Subs]}),
+ {Sub, SubId}.
+
+unsub_with_subid(Nidx, SubId, #pubsub_state{stateid = {Entity, _}} = SubState) ->
+ pubsub_subscription:delete_subscription(SubState#pubsub_state.stateid, Nidx, SubId),
+ NewSubs = [{S, Sid}
+ || {S, Sid} <- SubState#pubsub_state.subscriptions,
+ SubId =/= Sid],
case {NewSubs, SubState#pubsub_state.affiliation} of
- {[], none} ->
- del_state(NodeIdx, Entity);
- _ ->
- set_state(SubState#pubsub_state{subscriptions = NewSubs})
+ {[], none} -> del_state(Nidx, Entity);
+ _ -> set_state(SubState#pubsub_state{subscriptions = NewSubs})
end.
-%% TODO : doc
-%% @spec (Host, Owner) -> {result, Reply} | {error, Reason}
-%% Host = mod_pubsub:hostPubsub()
-%% Owner = mod_pubsub:jid()
-%% Reply = [] | [mod_pubsub:nodeId()]
%% @doc <p>Returns a list of Owner's nodes on Host with pending
%% subscriptions.</p>
--spec(get_pending_nodes/2 ::
-(
- Host :: mod_pubsub:host(),
- Owner :: jid())
- -> {result, [mod_pubsub:nodeId()]}
-).
-
get_pending_nodes(Host, Owner) ->
GenKey = jlib:jid_remove_resource(jlib:jid_tolower(Owner)),
- States = mnesia:match_object(#pubsub_state{stateid =
- {GenKey, '_'},
- affiliation = owner, _ = '_'}),
- NodeIDs = [ID
- || #pubsub_state{stateid = {_, ID}} <- States],
- NodeTree = case catch
- ets:lookup(gen_mod:get_module_proc(Host, config),
- nodetree)
- of
- [{nodetree, N}] -> N;
- _ -> nodetree_tree
- end,
- Reply = mnesia:foldl(fun (#pubsub_state{stateid = {_, NID}} = S,
- Acc) ->
- case lists:member(NID, NodeIDs) of
- true ->
- case get_nodes_helper(NodeTree, S) of
- {value, Node} -> [Node | Acc];
- false -> Acc
- end;
- false -> Acc
- end
- end,
- [], pubsub_state),
+ States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'},
+ affiliation = owner,
+ _ = '_'}),
+ NodeIdxs = [Nidx || #pubsub_state{stateid = {_, Nidx}} <- States],
+ NodeTree = mod_pubsub:tree(Host),
+ Reply = mnesia:foldl(fun (#pubsub_state{stateid = {_, Nidx}} = S, Acc) ->
+ case lists:member(Nidx, NodeIdxs) of
+ true ->
+ case get_nodes_helper(NodeTree, S) of
+ {value, Node} -> [Node | Acc];
+ false -> Acc
+ end;
+ false ->
+ Acc
+ end
+ end,
+ [], pubsub_state),
{result, Reply}.
--spec(get_nodes_helper/2 ::
-(
- NodeTree :: module(),
- Pubsub_State :: mod_pubsub:pubsubState())
- -> {value, NodeId::mod_pubsub:nodeId()}
- | false
-
-).
get_nodes_helper(NodeTree, #pubsub_state{stateid = {_, N}, subscriptions = Subs}) ->
- HasPending = fun ({pending, _}) -> true;
- (pending) -> true;
- (_) -> false
- end,
+ HasPending = fun
+ ({pending, _}) -> true;
+ (pending) -> true;
+ (_) -> false
+ end,
case lists:any(HasPending, Subs) of
- true ->
- case NodeTree:get_node(N) of
- #pubsub_node{nodeid = {_, Node}} -> {value, Node};
- _ -> false
- end;
- false -> false
+ true ->
+ case NodeTree:get_node(N) of
+ #pubsub_node{nodeid = {_, Node}} -> {value, Node};
+ _ -> false
+ end;
+ false ->
+ false
end.
-%% @spec (NodeIdx) -> {result, States}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% States = [] | [mod_pubsub:pubsubState()]
%% @doc Returns the list of stored states for a given node.
%% <p>For the default PubSub module, states are stored in Mnesia database.</p>
%% <p>We can consider that the pubsub_state table have been created by the main
@@ -1028,72 +683,33 @@ get_nodes_helper(NodeTree, #pubsub_state{stateid = {_, N}, subscriptions = Subs}
%% relational database).</p>
%% <p>If a PubSub plugin wants to delegate the states storage to the default node,
%% they can implement this function like this:
-%% ```get_states(NodeIdx) ->
-%% node_default:get_states(NodeIdx).'''</p>
--spec(get_states/1 ::
-(
- NodeIdx::mod_pubsub:nodeIdx())
- -> {result, [mod_pubsub:pubsubState()]}
-).
-
-get_states(NodeIdx) ->
+%% ```get_states(Nidx) ->
+%% node_default:get_states(Nidx).'''</p>
+get_states(Nidx) ->
States = case catch mnesia:match_object(
- #pubsub_state{stateid = {'_', NodeIdx}, _ = '_'}) of
+ #pubsub_state{stateid = {'_', Nidx}, _ = '_'}) of
List when is_list(List) -> List;
_ -> []
end,
{result, States}.
-%% @spec (NodeIdx, JID) -> State
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% JID = mod_pubsub:jid()
-%% State = mod_pubsub:pubsubState()
%% @doc <p>Returns a state (one state list), given its reference.</p>
--spec(get_state/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- JID :: ljid())
- -> mod_pubsub:pubsubState()
-).
-
-get_state(NodeIdx, JID) ->
- StateId = {JID, NodeIdx},
+get_state(Nidx, Key) ->
+ StateId = {Key, Nidx},
case catch mnesia:read({pubsub_state, StateId}) of
[State] when is_record(State, pubsub_state) -> State;
- _ -> #pubsub_state{stateid=StateId}
+ _ -> #pubsub_state{stateid = StateId}
end.
-%% @spec (State) -> ok | {error, Reason}
-%% State = mod_pubsub:pubsubState()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Write a state into database.</p>
--spec(set_state/1 ::
-(
- State::mod_pubsub:pubsubState())
- -> ok
-).
set_state(State) when is_record(State, pubsub_state) ->
mnesia:write(State).
%set_state(_) -> {error, ?ERR_INTERNAL_SERVER_ERROR}.
-%% @spec (NodeIdx, JID) -> ok | {error, Reason}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% JID = mod_pubsub:jid()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Delete a state from database.</p>
--spec(del_state/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- JID :: ljid())
- -> ok
-).
-del_state(NodeIdx, JID) ->
- mnesia:delete({pubsub_state, {JID, NodeIdx}}).
+del_state(Nidx, Key) ->
+ mnesia:delete({pubsub_state, {Key, Nidx}}).
-%% @spec (NodeIdx, From) -> {result, Items}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% From = mod_pubsub:jid()
-%% Items = [] | [mod_pubsub:pubsubItem()]
%% @doc Returns the list of stored items for a given node.
%% <p>For the default PubSub module, items are stored in Mnesia database.</p>
%% <p>We can consider that the pubsub_item table have been created by the main
@@ -1102,228 +718,134 @@ del_state(NodeIdx, JID) ->
%% relational database), or they can even decide not to persist any items.</p>
%% <p>If a PubSub plugin wants to delegate the item storage to the default node,
%% they can implement this function like this:
-%% ```get_items(NodeIdx, From) ->
-%% node_default:get_items(NodeIdx, From).'''</p>
--spec(get_items/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- _From :: jid())
- -> {result, [mod_pubsub:pubsubItem()]}
-).
-
-get_items(NodeIdx, _From) ->
- Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeIdx}, _ = '_'}),
- {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}.
-
--spec(get_items/6 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- JID :: jid(),
- AccessModel :: mod_pubsub:accessModel(),
- Presence_Subscription :: boolean(),
- RosterGroup :: boolean(),
- _SubId :: mod_pubsub:subId())
- -> {result, [mod_pubsub:pubsubItem()]}
- %%%
- | {error, xmlel()}
-).
-
-get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
+%% ```get_items(Nidx, From) ->
+%% node_default:get_items(Nidx, From).'''</p>
+get_items(Nidx, From) ->
+ get_items(Nidx, From, none).
+get_items(Nidx, _From, _RSM) ->
+ Items = mnesia:match_object(#pubsub_item{itemid = {'_', Nidx}, _ = '_'}),
+ {result, {lists:reverse(lists:keysort(#pubsub_item.modification, Items)), none}}.
+
+get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, none).
+get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, _RSM) ->
SubKey = jlib:jid_tolower(JID),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
- SubState = get_state(NodeIdx, SubKey),
+ GenState = get_state(Nidx, GenKey),
+ SubState = get_state(Nidx, SubKey),
Affiliation = GenState#pubsub_state.affiliation,
Subscriptions = SubState#pubsub_state.subscriptions,
Whitelisted = can_fetch_item(Affiliation, Subscriptions),
if %%SubId == "", ?? ->
- %% Entity has multiple subscriptions to the node but does not specify a subscription ID
- %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
- %%InvalidSubId ->
- %% Entity is subscribed but specifies an invalid subscription ID
- %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
- GenState#pubsub_state.affiliation == outcast ->
- {error, ?ERR_FORBIDDEN};
- (AccessModel == presence) and
- not PresenceSubscription ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"presence-subscription-required">>)};
- (AccessModel == roster) and not RosterGroup ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"not-in-roster-group">>)};
- (AccessModel == whitelist) and not Whitelisted ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
- (AccessModel == authorize) and not Whitelisted ->
- {error, ?ERR_FORBIDDEN};
- %%MustPay ->
- %% % Payment is required for a subscription
- %% {error, ?ERR_PAYMENT_REQUIRED};
- true -> get_items(NodeIdx, JID)
+ %% Entity has multiple subscriptions to the node but does not specify a subscription ID
+ %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %%InvalidSubId ->
+ %% Entity is subscribed but specifies an invalid subscription ID
+ %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ Affiliation == outcast ->
+ {error, ?ERR_FORBIDDEN};
+ (AccessModel == presence) and not PresenceSubscription ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ (AccessModel == roster) and not RosterGroup ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ (AccessModel == whitelist) and not Whitelisted ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ (AccessModel == authorize) and not Whitelisted ->
+ {error, ?ERR_FORBIDDEN};
+ %%MustPay ->
+ %% % Payment is required for a subscription
+ %% {error, ?ERR_PAYMENT_REQUIRED};
+ true ->
+ get_items(Nidx, JID)
end.
-%% @spec (NodeIdx, ItemId) -> {result, Item} | {error, 'item-not-found'}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% ItemId = mod_pubsub:itemId()
-%% Item = mod_pubsub:pubsubItem()
%% @doc <p>Returns an item (one item list), given its reference.</p>
--spec(get_item/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- ItemId :: mod_pubsub:itemId())
- -> {result, mod_pubsub:pubsubItem()}
- | {error, xmlel()}
-).
-get_item(NodeIdx, ItemId) ->
- case mnesia:read({pubsub_item, {ItemId, NodeIdx}}) of
- [Item] when is_record(Item, pubsub_item) -> {result, Item};
- _ -> {error, ?ERR_ITEM_NOT_FOUND}
+get_item(Nidx, ItemId) ->
+ case mnesia:read({pubsub_item, {ItemId, Nidx}}) of
+ [Item] when is_record(Item, pubsub_item) -> {result, Item};
+ _ -> {error, ?ERR_ITEM_NOT_FOUND}
end.
-%% @spec (NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> {result, Item} | {error, Reason}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% ItemId = mod_pubsub:itemId()
-%% JID = mod_pubsub:jid()
-%% AccessModel = mod_pubsub:accessModel()
-%% PresenceSubscription = boolean()
-%% RosterGroup = boolean()
-%% SubId = mod_pubsub:subId()
-%% Item = mod_pubsub:pubsubItem()
-%% Reason = mod_pubsub:stanzaError() | 'item-not-found'
--spec(get_item/7 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- ItemId :: mod_pubsub:itemId(),
- JID :: jid(),
- AccessModel :: mod_pubsub:accessModel(),
- PresenceSubscription :: boolean(),
- RosterGroup :: boolean(),
- SubId :: mod_pubsub:subId())
- -> {result, mod_pubsub:pubsubItem()}
- | {error, xmlel()}
-).
-
-get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup,
- _SubId) ->
+get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
SubKey = jlib:jid_tolower(JID),
GenKey = jlib:jid_remove_resource(SubKey),
- GenState = get_state(NodeIdx, GenKey),
+ GenState = get_state(Nidx, GenKey),
Affiliation = GenState#pubsub_state.affiliation,
Subscriptions = GenState#pubsub_state.subscriptions,
Whitelisted = can_fetch_item(Affiliation, Subscriptions),
if %%SubId == "", ?? ->
- %% Entity has multiple subscriptions to the node but does not specify a subscription ID
- %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
- %%InvalidSubId ->
- %% Entity is subscribed but specifies an invalid subscription ID
- %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
- GenState#pubsub_state.affiliation == outcast ->
- {error, ?ERR_FORBIDDEN};
- (AccessModel == presence) and
- not PresenceSubscription ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED),
- <<"presence-subscription-required">>)};
- (AccessModel == roster) and not RosterGroup ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
- (AccessModel == whitelist) and not Whitelisted ->
- {error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
- (AccessModel == authorize) and not Whitelisted ->
- {error, ?ERR_FORBIDDEN};
- %%MustPay ->
- %% % Payment is required for a subscription
- %% {error, ?ERR_PAYMENT_REQUIRED};
- true -> get_item(NodeIdx, ItemId)
+ %% Entity has multiple subscriptions to the node but does not specify a subscription ID
+ %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %%InvalidSubId ->
+ %% Entity is subscribed but specifies an invalid subscription ID
+ %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ Affiliation == outcast ->
+ {error, ?ERR_FORBIDDEN};
+ (AccessModel == presence) and not PresenceSubscription ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ (AccessModel == roster) and not RosterGroup ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ (AccessModel == whitelist) and not Whitelisted ->
+ {error,
+ ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ (AccessModel == authorize) and not Whitelisted ->
+ {error, ?ERR_FORBIDDEN};
+ %%MustPay ->
+ %% % Payment is required for a subscription
+ %% {error, ?ERR_PAYMENT_REQUIRED};
+ true ->
+ get_item(Nidx, ItemId)
end.
-%% @spec (Item) -> ok | {error, Reason}
-%% Item = mod_pubsub:pubsubItem()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Write an item into database.</p>
--spec(set_item/1 ::
-(
- Item::mod_pubsub:pubsubItem())
- -> ok
-).
set_item(Item) when is_record(Item, pubsub_item) ->
mnesia:write(Item).
%set_item(_) -> {error, ?ERR_INTERNAL_SERVER_ERROR}.
-%% @spec (NodeIdx, ItemId) -> ok | {error, Reason}
-%% NodeIdx = mod_pubsub:nodeIdx()
-%% ItemId = mod_pubsub:itemId()
-%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Delete an item from database.</p>
--spec(del_item/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- ItemId :: mod_pubsub:itemId())
- -> ok
-).
-del_item(NodeIdx, ItemId) ->
- mnesia:delete({pubsub_item, {ItemId, NodeIdx}}).
+del_item(Nidx, ItemId) ->
+ mnesia:delete({pubsub_item, {ItemId, Nidx}}).
--spec(del_items/2 ::
-(
- NodeIdx :: mod_pubsub:nodeIdx(),
- ItemIds :: [mod_pubsub:pubsubItem(),...])
- -> ok
-).
-
-del_items(NodeIdx, ItemIds) ->
- lists:foreach(fun (ItemId) -> del_item(NodeIdx, ItemId)
- end,
- ItemIds).
+del_items(Nidx, ItemIds) ->
+ lists:foreach(fun (ItemId) -> del_item(Nidx, ItemId)
+ end,
+ ItemIds).
-get_item_name(_Host, _Node, Id) -> Id.
+get_item_name(_Host, _Node, Id) ->
+ Id.
%% @doc <p>Return the name of the node if known: Default is to return
%% node id.</p>
--spec(node_to_path/1 ::
-(
- Node::binary())
- -> [binary()]
-).
-node_to_path(Node) -> str:tokens((Node), <<"/">>).
-
--spec(path_to_node/1 ::
-(
- Path :: [binary()])
- -> binary()
-).
+node_to_path(Node) ->
+ str:tokens(Node, <<"/">>).
path_to_node([]) -> <<>>;
-path_to_node(Path) ->
- iolist_to_binary(str:join([<<"">> | Path], <<"/">>)).
+path_to_node(Path) -> iolist_to_binary(str:join([<<"">> | Path], <<"/">>)).
-%% @spec (Affiliation, Subscription) -> true | false
-%% Affiliation = owner | member | publisher | outcast | none
-%% Subscription = subscribed | none
-%% @doc Determines if the combination of Affiliation and Subscribed
-%% are allowed to get items from a node.
can_fetch_item(owner, _) -> true;
can_fetch_item(member, _) -> true;
can_fetch_item(publisher, _) -> true;
can_fetch_item(outcast, _) -> false;
-can_fetch_item(none, Subscriptions) ->
- is_subscribed(Subscriptions).
+can_fetch_item(none, Subscriptions) -> is_subscribed(Subscriptions).
%can_fetch_item(_Affiliation, _Subscription) -> false.
is_subscribed(Subscriptions) ->
- lists:any(fun ({subscribed, _SubId}) -> true;
- (_) -> false
- end,
- Subscriptions).
+ lists:any(fun
+ ({subscribed, _SubId}) -> true;
+ (_) -> false
+ end,
+ Subscriptions).
-%% Returns the first item where Pred() is true in List
-first_in_list(_Pred, []) -> false;
+first_in_list(_Pred, []) ->
+ false;
first_in_list(Pred, [H | T]) ->
case Pred(H) of
- true -> {value, H};
- _ -> first_in_list(Pred, T)
+ true -> {value, H};
+ _ -> first_in_list(Pred, T)
end.