./ct_report/coverage/mod_mam_mnesia_prefs.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% @author Uvarov Michael <arcusfelis@gmail.com>
3 %%% @copyright (C) 2013, Uvarov Michael
4 %%% @doc A backend for storing MAM preferencies using Mnesia.
5 %%%
6 %%% All preferencies of each user are stored inside a single row.
7 %%% All operations are dirty.
8 %%% @end
9 %%%-------------------------------------------------------------------
10 -module(mod_mam_mnesia_prefs).
11
12 %% ----------------------------------------------------------------------
13 %% Exports
14
15 %% gen_mod handlers
16 -export([start/2, stop/1, supported_features/0]).
17
18 %% MAM hook handlers
19 -behaviour(ejabberd_gen_mam_prefs).
20 -export([get_behaviour/5,
21 get_prefs/4,
22 set_prefs/7,
23 remove_archive/4]).
24
25 -ignore_xref([remove_archive/4, start/2, stop/1, supported_features/0]).
26
27 -include("mongoose.hrl").
28 -include("jlib.hrl").
29 -include_lib("exml/include/exml.hrl").
30
31 -record(mam_prefs, {host_user :: {jid:server(), jid:user()},
32 default_mode,
33 always_rules :: list(),
34 never_rules :: list()
35 }).
36 -type mam_prefs() :: #mam_prefs{}.
37 -type behaviour() :: 'always' | 'never' | 'roster'.
38
39 %% ----------------------------------------------------------------------
40 %% gen_mod callbacks
41 %% Starting and stopping functions for users' archives
42
43 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
44 start(HostType, Opts) ->
45 16 mnesia:create_table(mam_prefs,
46 [{disc_copies, [node()]},
47 {attributes, record_info(fields, mam_prefs)}]),
48 16 mnesia:add_table_copy(mam_prefs, node(), disc_copies),
49 16 ejabberd_hooks:add(hooks(HostType, Opts)).
50
51 -spec stop(mongooseim:host_type()) -> ok.
52 stop(HostType) ->
53 16 Opts = gen_mod:get_loaded_module_opts(HostType, ?MODULE),
54 16 ejabberd_hooks:delete(hooks(HostType, Opts)).
55
56 -spec supported_features() -> [atom()].
57 supported_features() ->
58 16 [dynamic_domains].
59
60 %% ----------------------------------------------------------------------
61 %% Hooks
62
63 hooks(HostType, Opts) ->
64 32 lists:flatmap(fun(Type) -> hooks(HostType, Type, Opts) end, [pm, muc]).
65
66 hooks(HostType, pm, #{pm := true}) ->
67 28 [{mam_get_behaviour, HostType, ?MODULE, get_behaviour, 50},
68 {mam_get_prefs, HostType, ?MODULE, get_prefs, 50},
69 {mam_set_prefs, HostType, ?MODULE, set_prefs, 50},
70 {mam_remove_archive, HostType, ?MODULE, remove_archive, 50}];
71 hooks(HostType, muc, #{muc := true}) ->
72 8 [{mam_muc_get_behaviour, HostType, ?MODULE, get_behaviour, 50},
73 {mam_muc_get_prefs, HostType, ?MODULE, get_prefs, 50},
74 {mam_muc_set_prefs, HostType, ?MODULE, set_prefs, 50},
75 {mam_muc_remove_archive, HostType, ?MODULE, remove_archive, 50}];
76 hooks(_HostType, _Opt, _Opts) ->
77 28 [].
78
79 %% ----------------------------------------------------------------------
80 %% Internal functions and callbacks
81
82 -spec get_behaviour(Default :: behaviour(), Host :: jid:server(),
83 ArcID :: mod_mam:archive_id(), LocJID :: jid:jid(),
84 RemJID :: jid:jid()) -> any().
85 get_behaviour(DefaultBehaviour, _Host,
86 _ArcID,
87 LocJID=#jid{},
88 RemJID=#jid{}) ->
89 724 SU = su_key(LocJID),
90 724 case mnesia:dirty_read(mam_prefs, SU) of
91 556 [] -> DefaultBehaviour;
92 168 [User] -> get_behaviour(User, LocJID, RemJID)
93 end.
94
95
96 -spec get_behaviour(mam_prefs(), LocJID :: jid:jid(),
97 RemJID :: jid:jid()) -> behaviour().
98 get_behaviour(#mam_prefs{default_mode = always, never_rules=NeverJIDs}, LocJID, RemJID) ->
99 56 IsNever = match_jid(LocJID, RemJID, NeverJIDs),
100 56 case IsNever of
101 16 true -> never;
102 40 false -> always
103 end;
104 get_behaviour(#mam_prefs{default_mode = never, always_rules=AlwaysJIDs}, LocJID, RemJID) ->
105 56 IsAlways = match_jid(LocJID, RemJID, AlwaysJIDs),
106 56 case IsAlways of
107 16 true -> always;
108 40 false -> never
109 end;
110 get_behaviour(#mam_prefs{default_mode = roster,
111 never_rules=NeverJIDs, always_rules=AlwaysJIDs}, LocJID, RemJID) ->
112 56 IsNever = match_jid(LocJID, RemJID, NeverJIDs),
113 56 case IsNever of
114 16 true -> never;
115 false ->
116 40 IsAlways = match_jid(LocJID, RemJID, AlwaysJIDs),
117 40 case IsAlways of
118 16 true -> always;
119 24 false -> roster
120 end
121 end.
122
123
124 -spec set_prefs(Result :: any(), Host :: jid:server(),
125 ArcID :: mod_mam:archive_id(), ArcJID :: jid:jid(),
126 DefaultMode :: mod_mam:archive_behaviour(),
127 AlwaysJIDs :: [jid:literal_jid()],
128 NeverJIDs :: [jid:literal_jid()]) -> any().
129 set_prefs(_Result, _Host, ArcID, ArcJID, DefaultMode, AlwaysJIDs, NeverJIDs) ->
130 88 try
131 88 set_prefs1(ArcID, ArcJID, DefaultMode, AlwaysJIDs, NeverJIDs)
132 catch _Type:Error ->
133
:-(
{error, Error}
134 end.
135
136 set_prefs1(_ArcID, ArcJID, DefaultMode, AlwaysJIDs, NeverJIDs) ->
137 88 SU = su_key(ArcJID),
138 88 NewARules = lists:usort(rules(ArcJID, AlwaysJIDs)),
139 88 NewNRules = lists:usort(rules(ArcJID, NeverJIDs)),
140 88 User = #mam_prefs{
141 host_user = SU,
142 default_mode = DefaultMode,
143 always_rules = NewARules,
144 never_rules = NewNRules
145 },
146 88 mnesia:sync_dirty(fun() ->
147 88 mnesia:write(User)
148 end),
149 88 ok.
150
151
152 -spec get_prefs(mod_mam:preference(), _Host :: jid:server(),
153 _ArcId :: mod_mam:archive_id(), ArcJID :: jid:jid()
154 ) -> mod_mam:preference().
155 get_prefs({GlobalDefaultMode, _, _}, _Host, _ArcID, ArcJID) ->
156 46 SU = su_key(ArcJID),
157 46 case mnesia:dirty_read(mam_prefs, SU) of
158 [] ->
159
:-(
{GlobalDefaultMode, [], []};
160 [#mam_prefs{default_mode=DefaultMode,
161 always_rules=ARules, never_rules=NRules}] ->
162 46 AlwaysJIDs = jids(ArcJID, ARules),
163 46 NeverJIDs = jids(ArcJID, NRules),
164 46 {DefaultMode, AlwaysJIDs, NeverJIDs}
165 end.
166
167 remove_archive(Acc, _Host, _ArcID, ArcJID) ->
168 138 remove_archive(ArcJID),
169 138 Acc.
170
171 remove_archive(ArcJID) ->
172 138 SU = su_key(ArcJID),
173 138 mnesia:sync_dirty(fun() ->
174 138 mnesia:delete(mam_prefs, SU, write)
175 end).
176
177 %% ----------------------------------------------------------------------
178 %% Helpers
179
180 -spec su_key(jid:jid()) -> jid:simple_bare_jid().
181 su_key(#jid{lserver=LocLServer, luser=LocLUser}) ->
182 996 {LocLServer, LocLUser}.
183
184
185 -spec jids(jid:jid(),
186 [jid:literal_jid() | jid:simple_bare_jid() | jid:simple_jid()]
187 ) -> [jid:literal_jid()].
188 jids(ArcJID, Rules) ->
189 92 [jid:to_binary(rule_to_jid(ArcJID, Rule)) || Rule <- Rules].
190
191
192 -spec rule_to_jid(jid:jid(),
193 jid:luser() | jid:simple_bare_jid() | jid:simple_jid()
194 ) -> jid:simple_jid().
195 rule_to_jid(#jid{lserver=LServer}, RemLUser) when is_binary(RemLUser) ->
196 48 {RemLUser, LServer, <<>>};
197 rule_to_jid(_ArcJID, {RemLServer, RemLUser, RemLResource}) ->
198
:-(
{RemLUser, RemLServer, RemLResource};
199 rule_to_jid(_ArcJID, {RemLServer, RemLUser}) ->
200 8 {RemLUser, RemLServer, <<>>}.
201
202
203 -spec rules(jid:jid(), [jid:literal_jid()]) ->
204 [jid:literal_jid() | jid:simple_bare_jid() | jid:simple_jid()].
205 rules(ArcJID, BinJIDs) ->
206 176 [rule(ArcJID, jid:from_binary(BinJID)) || BinJID <- BinJIDs].
207
208
209 -spec rule(jid:jid(), jid:jid()) ->
210 jid:literal_jid() | jid:simple_bare_jid() | jid:simple_jid().
211 rule(#jid{lserver=LServer}, #jid{lserver=LServer, luser=RemLUser, lresource = <<>>}) ->
212 304 RemLUser;
213 rule(_ArcJID, #jid{lserver=RemLServer, luser=RemLUser, lresource = <<>>}) ->
214 8 {RemLServer, RemLUser};
215 rule(_ArcJID, #jid{lserver=RemLServer, luser=RemLUser, lresource=RemLResource}) ->
216 144 {RemLServer, RemLUser, RemLResource}.
217
218
219 -spec is_bare_jid(jid:jid()) -> boolean().
220
:-(
is_bare_jid(#jid{lresource = <<>>}) -> true;
221 208 is_bare_jid(_) -> false.
222
223
224 -spec match_jid(jid:jid(), jid:jid(), [any()]) -> boolean().
225 match_jid(ArcJID, JID, JIDs) ->
226 208 case is_bare_jid(JID) of
227 true ->
228
:-(
ordsets:is_element(rule(ArcJID, JID), JIDs);
229 false ->
230 208 BareJID = jid:to_bare(JID),
231 208 ordsets:is_element(rule(ArcJID, BareJID), JIDs)
232 orelse
233 144 ordsets:is_element(rule(ArcJID, JID), JIDs)
234 end.
Line Hits Source