./ct_report/coverage/nodetree_dag.COVER.html

1 %%% XEP-0248: PubSub Collection Nodes
2 %%% DAG stands for Directed Acyclic Graph
3 %%%
4 %%% ====================================================================
5 %%% ``The contents of this file are subject to the Erlang Public License,
6 %%% Version 1.1, (the "License"); you may not use this file except in
7 %%% compliance with the License. You should have received a copy of the
8 %%% Erlang Public License along with this software. If not, it can be
9 %%% retrieved via the world wide web at http://www.erlang.org/.
10 %%%
11 %%%
12 %%% Software distributed under the License is distributed on an "AS IS"
13 %%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14 %%% the License for the specific language governing rights and limitations
15 %%% under the License.
16 %%%
17 %%%
18 %%% @author Brian Cully <bjc@kublai.com>
19 %%% @end
20 %%% ====================================================================
21
22 -module(nodetree_dag).
23 -behaviour(gen_pubsub_nodetree).
24 -author('bjc@kublai.com').
25
26 -include_lib("stdlib/include/qlc.hrl").
27
28 -include("pubsub.hrl").
29 -include("jlib.hrl").
30
31 -export([init/2, terminate/2, set_node/1,
32 get_node/2, get_node/1, get_nodes/2,
33 get_parentnodes_tree/3,
34 get_subnodes/3, create_node/6,
35 delete_node/2]).
36
37 -ignore_xref([{mod_pubsub_db_backend, get_parentnodes_tree, 2}]).
38
39 -define(DEFAULT_NODETYPE, leaf).
40 -define(DEFAULT_PARENTS, []).
41 -define(DEFAULT_CHILDREN, []).
42
43 init(HostType, Opts) ->
44 25 nodetree_tree:init(HostType, Opts).
45
46 terminate(Host, ServerHost) ->
47 25 nodetree_tree:terminate(Host, ServerHost).
48
49 set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} = Node) ->
50 156 Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
51 156 case validate_parentage(Key, Owners, Parents) of
52 156 true -> mod_pubsub_db_backend:set_node(Node#pubsub_node{parents = Parents});
53
:-(
Other -> Other
54 end.
55
56 create_node(Key, Node, Type, Owner, Options, Parents) ->
57 151 OwnerJID = jid:to_lower(jid:to_bare(Owner)),
58 151 case mod_pubsub_db_backend:find_node_by_name(Key, Node) of
59 false ->
60 151 N = #pubsub_node{nodeid = {Key, Node},
61 type = Type, parents = Parents, owners = [OwnerJID],
62 options = Options},
63 151 set_node(N);
64 _ ->
65
:-(
{error, mongoose_xmpp_errors:conflict()}
66 end.
67
68 delete_node(Key, Node) ->
69 88 case mod_pubsub_db_backend:find_node_by_name(Key, Node) of
70 false ->
71
:-(
{error, mongoose_xmpp_errors:item_not_found()};
72 Record ->
73 88 lists:foreach(fun (#pubsub_node{options = Opts} = Child) ->
74 1 NewOpts = remove_config_parent(Node, Opts),
75 1 Parents = find_opt(collection, ?DEFAULT_PARENTS, NewOpts),
76 1 {ok, _} = mod_pubsub_db_backend:set_node(
77 Child#pubsub_node{parents = Parents,
78 options = NewOpts})
79 end,
80 get_subnodes(Key, Node)),
81 88 mod_pubsub_db_backend:delete_node(Record),
82 88 [Record]
83 end.
84
85 get_node(Key, Node) ->
86 412 case mod_pubsub_db_backend:find_node_by_name(Key, Node) of
87 14 false -> {error, mongoose_xmpp_errors:item_not_found()};
88 398 Record -> Record
89 end.
90
91 get_node(Node) ->
92 243 nodetree_tree:get_node(Node).
93
94 get_nodes(Key, From) ->
95 30 nodetree_tree:get_nodes(Key, From).
96
97 get_parentnodes_tree(Key, Node, _From) ->
98 309 mod_pubsub_db_backend:get_parentnodes_tree(Key, Node).
99
100 get_subnodes(Host, Node, _From) ->
101 6 get_subnodes(Host, Node).
102
103 get_subnodes(Host, <<>>) ->
104 4 mod_pubsub_db_backend:get_subnodes(Host, <<>>);
105
106 get_subnodes(Host, Node) ->
107 90 case mod_pubsub_db_backend:find_node_by_name(Host, Node) of
108
:-(
false -> {error, mongoose_xmpp_errors:item_not_found()};
109 90 _ -> mod_pubsub_db_backend:get_subnodes(Host, Node)
110 end.
111
112 %%====================================================================
113 %% Internal functions
114 %%====================================================================
115
116 %% Key = jid:jid() | host()
117 %% Default = term()
118 %% Options = [{Key = atom(), Value = term()}]
119 find_opt(Key, Default, Options) ->
120 178 case lists:keysearch(Key, 1, Options) of
121 42 {value, {Key, Val}} -> Val;
122 136 _ -> Default
123 end.
124
125 remove_config_parent(Node, Options) ->
126 1 remove_config_parent(Node, Options, []).
127
128 remove_config_parent(_Node, [], Acc) ->
129 1 lists:reverse(Acc);
130 remove_config_parent(Node, [{collection, Parents} | T], Acc) ->
131 1 remove_config_parent(Node, T, [{collection, lists:delete(Node, Parents)} | Acc]);
132 remove_config_parent(Node, [H | T], Acc) ->
133 17 remove_config_parent(Node, T, [H | Acc]).
134
135 -spec validate_parentage(
136 Key :: mod_pubsub:hostPubsub(),
137 Owners :: [jid:ljid(), ...],
138 ParentNodes :: [mod_pubsub:nodeId()])
139 -> true | {error, exml:element()}.
140 validate_parentage(_Key, _Owners, []) ->
141 156 true;
142 validate_parentage(Key, Owners, [[] | T]) ->
143
:-(
validate_parentage(Key, Owners, T);
144 validate_parentage(Key, Owners, [<<>> | T]) ->
145
:-(
validate_parentage(Key, Owners, T);
146 validate_parentage(Key, Owners, [ParentID | T]) ->
147 21 case mod_pubsub_db_backend:find_node_by_name(Key, ParentID) of
148 false ->
149
:-(
{error, mongoose_xmpp_errors:item_not_found()};
150 #pubsub_node{owners = POwners, options = POptions} ->
151 21 NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
152 21 MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
153 21 case {MutualOwners, NodeType} of
154
:-(
{[], _} -> {error, mongoose_xmpp_errors:forbidden()};
155 21 {_, collection} -> validate_parentage(Key, Owners, T);
156
:-(
{_, _} -> {error, mongoose_xmpp_errors:not_allowed()}
157 end
158 end.
Line Hits Source