• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

esl / MongooseIM / 16620276937

30 Jul 2025 10:38AM UTC coverage: 85.578% (-0.07%) from 85.65%
16620276937

push

github

web-flow
Merge pull request #4549 from esl/erlang-28

Support Erlang 28

50 of 68 new or added lines in 5 files covered. (73.53%)

20 existing lines in 9 files now uncovered.

28946 of 33824 relevant lines covered (85.58%)

51769.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.65
/src/pubsub/node_pep.erl
1
%%% ====================================================================
2
%%% ``The contents of this file are subject to the Erlang Public License,
3
%%% Version 1.1, (the "License"); you may not use this file except in
4
%%% compliance with the License. You should have received a copy of the
5
%%% Erlang Public License along with this software. If not, it can be
6
%%% retrieved via the world wide web at http://www.erlang.org/.
7
%%%
8
%%%
9
%%% Software distributed under the License is distributed on an "AS IS"
10
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11
%%% the License for the specific language governing rights and limitations
12
%%% under the License.
13
%%%
14
%%%
15
%%% The Initial Developer of the Original Code is ProcessOne.
16
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
17
%%% All Rights Reserved.''
18
%%% This software is copyright 2006-2015, ProcessOne.
19
%%%
20
%%% @copyright 2006-2015 ProcessOne
21
%%% @author Christophe Romain <christophe.romain@process-one.net>
22
%%%   [http://www.process-one.net/]
23
%%% @end
24
%%% ====================================================================
25

26
-module(node_pep).
27
-behaviour(gen_pubsub_node).
28
-author('christophe.romain@process-one.net').
29

30
-include("mongoose.hrl").
31
-include("pubsub.hrl").
32
-include("jlib.hrl").
33

34
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
35
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
36

37
-export([based_on/0, init/3, terminate/2, options/0, features/0,
38
         create_node_permission/6, delete_node/1,
39
         unsubscribe_node/4, node_to_path/1,
40
         get_entity_affiliations/2, get_entity_affiliations/3,
41
         get_entity_subscriptions/2, get_entity_subscriptions/4,
42
         should_delete_when_owner_removed/0, check_publish_options/2
43
        ]).
44

45
-ignore_xref([get_entity_affiliations/3, get_entity_subscriptions/4, check_publish_options/2]).
46

47
based_on() ->  node_flat.
825✔
48

49
init(Host, ServerHost, Opts) ->
50
    node_flat:init(Host, ServerHost, Opts),
27✔
51
    complain_if_modcaps_disabled(ServerHost),
27✔
52
    ok.
27✔
53

54
terminate(Host, ServerHost) ->
55
    node_flat:terminate(Host, ServerHost),
27✔
56
    ok.
27✔
57

58
options() ->
59
    [{deliver_payloads, true},
157✔
60
        {notify_config, false},
61
        {notify_delete, false},
62
        {notify_retract, false},
63
        {purge_offline, false},
64
        {persist_items, true},
65
        {max_items, 1},
66
        {subscribe, true},
67
        {access_model, presence},
68
        {roster_groups_allowed, []},
69
        {publish_model, publishers},
70
        {notification_type, headline},
71
        {max_payload_size, ?MAX_PAYLOAD_SIZE},
72
        {send_last_published_item, on_sub_and_presence},
73
        {deliver_notifications, true},
74
        {presence_based_delivery, true}].
75

76
features() ->
77
    [<<"create-nodes">>,
1,700✔
78
        <<"auto-create">>,
79
        <<"auto-subscribe">>,
80
        <<"delete-nodes">>,
81
        <<"delete-items">>,
82
        <<"filtered-notifications">>,
83
        <<"modify-affiliations">>,
84
        <<"outcast-affiliation">>,
85
        <<"persistent-items">>,
86
        <<"publish">>,
87
        <<"publish-options">>,
88
        <<"purge-nodes">>,
89
        <<"retract-items">>,
90
        <<"retrieve-affiliations">>,
91
        <<"retrieve-items">>,
92
        <<"retrieve-subscriptions">>,
93
        <<"subscribe">>].
94

95
-spec check_publish_options(#{binary() => [binary()]} | invalid_form, #{binary() => [binary()]}) ->
96
    boolean().
97
check_publish_options(invalid_form, _) ->
98
    true;
7✔
99
check_publish_options(PublishOptions, NodeOptions) ->
100
    F = fun(Key, Value) ->
168✔
101
            case string:split(Key, "#") of
140✔
102
                [<<"pubsub">>, Key2] ->
103
                    compare_values(Value, maps:get(Key2, NodeOptions, null));
133✔
104
                _ -> true
7✔
105
            end
106
        end,
107
    maps:size(maps:filter(F, PublishOptions)) =/= 0.
168✔
108

109
-spec compare_values([binary()], [binary()] | null) -> boolean().
110
compare_values(_, null) ->
111
    true;
7✔
112
compare_values(Value1, Value2) ->
113
    lists:sort(Value1) =/= lists:sort(Value2).
126✔
114

115
create_node_permission(Host, _ServerHost, _Node, _ParentNode,
116
                       #jid{ luser = <<>>, lserver = Host, lresource = <<>> }, _Access) ->
117
    {result, true}; % pubsub service always allowed
×
118
create_node_permission(Host, ServerHost, _Node, _ParentNode,
119
                       #jid{ luser = User, lserver = Server } = Owner, Access) ->
120
    {ok, HostType} = mongoose_domain_api:get_domain_host_type(ServerHost),
158✔
121
    case acl:match_rule(HostType, ServerHost, Access, Owner) of
158✔
122
        allow ->
123
            case Host of
158✔
124
                {User, Server, _} -> {result, true};
158✔
125
                _ -> {result, false}
×
126
            end;
127
        _ ->
128
            {result, false}
×
129
    end.
130

131
delete_node(Nodes) ->
132
    {result, {_, _, Result}} = node_flat:delete_node(Nodes),
29✔
133
    {result, {[], Result}}.
29✔
134

135
unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
136
    case node_flat:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
×
137
        {error, Error} -> {error, Error};
×
138
        {result, _} -> {result, []}
×
139
    end.
140

141
get_entity_affiliations(Host, #jid{ lserver = D } = Owner) ->
142
    get_entity_affiliations(Host, D, jid:to_lower(Owner));
×
143
get_entity_affiliations(Host, {_, D, _} = Owner) ->
144
    get_entity_affiliations(Host, D, Owner).
457✔
145

146
get_entity_affiliations(Host, D, Owner) ->
147
    {ok, States} = mod_pubsub_db_backend:get_states_by_bare(Owner),
457✔
148
    HT = mod_pubsub:host_to_host_type(Host),
457✔
149
    NodeTree = mod_pubsub:tree(HT),
457✔
150
    Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) ->
457✔
151
                    case gen_pubsub_nodetree:get_node(NodeTree, N) of
176✔
152
                        #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A} | Acc];
112✔
153
                        _ -> Acc
64✔
154
                    end
155
            end,
156
            [], States),
157
    {result, Reply}.
457✔
158

159
get_entity_subscriptions(Host, #jid{ lserver = D, lresource = R } = Owner) ->
160
    get_entity_subscriptions(Host, D, R, Owner);
481✔
161
get_entity_subscriptions(Host, {_, D, R} = Owner) ->
162
    get_entity_subscriptions(Host, D, R, Owner).
×
163

164
get_entity_subscriptions(Host, D, R, Owner) ->
165
    LOwner = jid:to_lower(Owner),
481✔
166
    States = case R of
481✔
167
                 <<>> ->
168
                     {ok, States0} = mod_pubsub_db_backend:get_states_by_lus(LOwner),
24✔
169
                     States0;
24✔
170
                 _ ->
171
                     {ok, States0} = mod_pubsub_db_backend:get_states_by_bare_and_full(LOwner),
457✔
172
                     States0
457✔
173
             end,
174
    HT = mod_pubsub:host_to_host_type(Host),
481✔
175
    NodeTree = mod_pubsub:tree(HT),
481✔
176
    Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) ->
481✔
177
                    case gen_pubsub_nodetree:get_node(NodeTree, N) of
9✔
178
                        #pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
179
                            accumulate_entity_subscriptions(J, Node, Ss, Acc);
9✔
180
                        _ ->
UNCOV
181
                            Acc
×
182
                    end
183
            end,
184
            [], States),
185
    {result, Reply}.
481✔
186

187
accumulate_entity_subscriptions(J, Node, Ss, Acc) ->
188
    lists:foldl(fun({subscribed, SubId}, Acc2) ->
9✔
189
                        [{Node, subscribed, SubId, J} | Acc2];
×
190
                   ({pending, _SubId}, Acc2) ->
191
                        [{Node, pending, J} | Acc2];
7✔
192
                   (S, Acc2) ->
193
                        [{Node, S, J} | Acc2]
×
194
                end, Acc, Ss).
195

196

197
node_to_path(Node) ->
198
    node_flat:node_to_path(Node).
158✔
199

200
should_delete_when_owner_removed() -> true.
16✔
201

202
%%%
203
%%% Internal
204
%%%
205

206
%% @doc Check mod_caps is enabled, otherwise show warning.
207
%% The PEP plugin for mod_pubsub requires mod_caps to be enabled in the host.
208
%% Check that the mod_caps module is enabled in that Jabber Host
209
%% If not, log a warning message.
210
complain_if_modcaps_disabled(ServerHost) ->
211
    ?WARNING_MSG_IF(
27✔
212
       not gen_mod:is_loaded(ServerHost, mod_caps),
27✔
213
       "The PEP plugin is enabled in mod_pubsub "
214
       "of host ~p. This plugin requires mod_caps "
215
       "to be enabled, but it isn't.",
216
       [ServerHost]).
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc