./ct_report/coverage/mod_inbox_utils.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% @copyright (C) 2018, Erlang-Solutions
3 %%% @doc
4 %%%
5 %%% @end
6 %%% Created : 30. Jan 2018 13:22
7 %%%-------------------------------------------------------------------
8 -module(mod_inbox_utils).
9
10 -include("mod_inbox.hrl").
11 -include("jlib.hrl").
12
13 -type inbox_fun() :: fun((mongooseim:host_type(),
14 jid:jid(),
15 jid:jid(),
16 exml:element(),
17 mongoose_acc:t()) -> mod_inbox:count_res()).
18
19 %%%%%%%%%%%%%%%%%%%
20 %% DB Operations shared by mod_inbox_one2one and mod_inbox_muclight
21 -export([maybe_reset_unread_count/5,
22 reset_unread_count_to_zero/3,
23 maybe_write_to_inbox/6,
24 write_to_sender_inbox/5,
25 write_to_receiver_inbox/5,
26 clear_inbox/3,
27 get_reset_markers/1,
28 if_chat_marker_get_id/2,
29 has_chat_marker/1,
30 get_option_write_aff_changes/1,
31 get_option_remove_on_kicked/1,
32 extract_attr_jid/1,
33 maybe_binary_to_positive_integer/1,
34 binary_to_bool/1,
35 bool_to_binary/1,
36 build_inbox_entry_key/2,
37 build_forward_el/1,
38 all_valid_boxes_for_query/1,
39 list_single_form_field/3,
40 calculate_ts_from/2
41 ]).
42
43 -ignore_xref([get_reset_markers/1, if_chat_marker_get_id/2]).
44
45 -spec maybe_reset_unread_count(HostType :: mongooseim:host_type(),
46 User :: jid:jid(),
47 Remote :: jid:jid(),
48 Packet :: exml:element(),
49 Acc :: mongoose_acc:t()) -> ok.
50 maybe_reset_unread_count(HostType, User, Remote, Packet, Acc) ->
51 384 ResetMarkers = get_reset_markers(HostType),
52 384 case if_chat_marker_get_id(Packet, ResetMarkers) of
53 undefined ->
54 261 ok;
55 Id ->
56 123 TS = mongoose_acc:timestamp(Acc),
57 123 reset_unread_count(HostType, User, Remote, Id, TS)
58 end.
59
60 -spec reset_unread_count_to_zero(mongoose_acc:t(), jid:jid(), jid:jid()) -> ok.
61 reset_unread_count_to_zero(Acc, From, Remote) ->
62 6 TS = mongoose_acc:timestamp(Acc),
63 6 HostType = mongoose_acc:host_type(Acc),
64 6 InboxEntryKey = build_inbox_entry_key(From, Remote),
65 6 ok = mod_inbox_backend:reset_unread(HostType, InboxEntryKey, undefined, TS).
66
67 -spec reset_unread_count(HostType ::mongooseim:host_type(),
68 From :: jid:jid(),
69 Remote :: jid:jid(),
70 MsgId :: id(),
71 TS :: integer()) -> ok.
72 reset_unread_count(HostType, From, Remote, MsgId, TS) ->
73 123 InboxEntryKey = build_inbox_entry_key(From, Remote),
74 123 ok = mod_inbox_backend:reset_unread(HostType, InboxEntryKey, MsgId, TS).
75
76 -spec write_to_sender_inbox(HostType :: mongooseim:host_type(),
77 Sender :: jid:jid(),
78 Receiver :: jid:jid(),
79 Packet :: exml:element(),
80 Acc :: mongoose_acc:t()) -> ok.
81 write_to_sender_inbox(HostType, Sender, Receiver, Packet, Acc) ->
82 253 MsgId = get_msg_id(Packet),
83 253 Timestamp = mongoose_acc:timestamp(Acc),
84 %% no unread for a user because he writes new messages which assumes he read all previous messages.
85 253 Count = 0,
86 253 InboxEntryKey = build_inbox_entry_key(Sender, Receiver),
87 253 mod_inbox_backend:set_inbox(HostType, InboxEntryKey, Packet, Count, MsgId, Timestamp).
88
89 -spec write_to_receiver_inbox(HostType :: mongooseim:host_type(),
90 Sender :: jid:jid(),
91 Receiver :: jid:jid(),
92 Packet :: exml:element(),
93 Acc :: mongoose_acc:t()) -> ok | {ok, integer()}.
94 write_to_receiver_inbox(HostType, Sender, Receiver, Packet, Acc) ->
95 416 MsgId = get_msg_id(Packet),
96 416 Timestamp = mongoose_acc:timestamp(Acc),
97 416 InboxEntryKey = build_inbox_entry_key(Receiver, Sender),
98 416 mod_inbox_backend:set_inbox_incr_unread(HostType, InboxEntryKey,
99 Packet, MsgId, Timestamp).
100
101 -spec clear_inbox(HostType :: mongooseim:host_type(),
102 User :: jid:user(),
103 Server :: jid:server()) -> mod_inbox:write_res().
104 clear_inbox(HostType, User, Server) when is_binary(User) ->
105 610 LUser = jid:nodeprep(User),
106 610 LServer = jid:nameprep(Server),
107 610 ok = mod_inbox_backend:clear_inbox(HostType, LUser, LServer).
108
109 %%%%%%%%%%%%%%%%%%%
110 %% Helpers
111
112 -spec get_reset_markers(HostType :: mongooseim:host_type()) -> list(marker()).
113 get_reset_markers(HostType) ->
114 384 gen_mod:get_module_opt(HostType, mod_inbox, reset_markers).
115
116 -spec if_chat_marker_get_id(Packet :: exml:element(),
117 Markers :: list(marker())) -> undefined | id().
118 if_chat_marker_get_id(Packet, Markers) when is_list(Markers) ->
119 384 Ids = [if_chat_marker_get_id(Packet, M) || M <- Markers],
120 384 Filtered = [El || El <- Ids, El /= undefined],
121 384 case Filtered of
122 [] ->
123 261 undefined;
124 [H | _] ->
125 123 H
126 end;
127 if_chat_marker_get_id(Packet, Marker) ->
128 384 case exml_query:paths(Packet, [{element, Marker}, {attr, <<"id">>}]) of
129 [Id] ->
130 123 Id;
131 _ ->
132 261 undefined
133 end.
134
135
136 -spec has_chat_marker(Packet :: exml:element()) -> boolean().
137 has_chat_marker(Packet) ->
138 1079 mongoose_chat_markers:has_chat_markers(Packet).
139
140 -spec maybe_write_to_inbox(HostType, User, Remote, Packet, Acc, WriteF) ->
141 mod_inbox:count_res() when
142 HostType ::mongooseim:host_type(),
143 User :: jid:jid(),
144 Remote :: jid:jid(),
145 Packet :: exml:element(),
146 Acc :: mongoose_acc:t(),
147 %% WriteF is write_to_receiver_inbox/5 or write_to_sender_inbox/5
148 WriteF :: inbox_fun().
149 maybe_write_to_inbox(HostType, User, Remote, Packet, Acc, WriteF) ->
150 520 case has_chat_marker(Packet) of
151 true ->
152 80 ok;
153 false ->
154 440 Packet2 = fill_from_attr(Packet, User),
155 440 WriteF(HostType, User, Remote, Packet2, Acc)
156 end.
157
158 -spec get_msg_id(Msg :: exml:element()) -> binary().
159 get_msg_id(#xmlel{name = <<"message">>} = Msg) ->
160 669 exml_query:attr(Msg, <<"id">>, <<>>).
161
162 -spec fill_from_attr(Msg :: exml:element(), From :: jid:jid()) -> exml:element().
163 fill_from_attr(Msg = #xmlel{attrs = Attrs}, From) ->
164 440 case exml_query:attr(Msg, <<"from">>, undefined) of
165 undefined ->
166 400 FromBin = jid:to_binary(From),
167 400 Msg#xmlel{attrs = [{<<"from">>, FromBin} | Attrs]};
168 _ ->
169 40 Msg
170 end.
171
172 -spec get_option_write_aff_changes(HostType :: mongooseim:host_type()) -> boolean().
173 get_option_write_aff_changes(HostType) ->
174 131 gen_mod:get_module_opt(HostType, mod_inbox, aff_changes).
175
176 -spec get_option_remove_on_kicked(HostType :: mongooseim:host_type()) -> boolean().
177 get_option_remove_on_kicked(HostType) ->
178 21 gen_mod:get_module_opt(HostType, mod_inbox, remove_on_kicked).
179
180 extract_attr_jid(ResetStanza) ->
181 134 case exml_query:attr(ResetStanza, <<"jid">>) of
182 undefined ->
183 6 {error, <<"jid-required">>};
184 Value ->
185 128 case jid:from_binary(Value) of
186 error ->
187 4 {error, <<"invalid-jid">>};
188 124 JID -> JID
189 end
190 end.
191
192 -spec maybe_binary_to_positive_integer(binary()) -> non_neg_integer() | {error, atom()}.
193 maybe_binary_to_positive_integer(Bin) ->
194 33 try erlang:binary_to_integer(Bin) of
195 27 N when N >= 0 -> N;
196 2 _ -> {error, non_positive_integer}
197 4 catch error:badarg -> {error, 'NaN'}
198 end.
199
200 -spec binary_to_bool(binary()) -> true | false | error.
201 33 binary_to_bool(<<"true">>) -> true;
202 784 binary_to_bool(<<"false">>) -> false;
203 4 binary_to_bool(_) -> error.
204
205 -spec bool_to_binary(integer() | boolean()) -> binary() | error.
206
:-(
bool_to_binary(1) -> <<"true">>;
207
:-(
bool_to_binary(0) -> <<"false">>;
208 69 bool_to_binary(true) -> <<"true">>;
209 29 bool_to_binary(false) -> <<"false">>;
210
:-(
bool_to_binary(_) -> error.
211
212 build_inbox_entry_key(FromJid, ToJid) ->
213 921 {LUser, LServer} = jid:to_lus(FromJid),
214 921 ToBareJid = jid:nameprep(jid:to_binary(jid:to_lus(ToJid))),
215 921 {LUser, LServer, ToBareJid}.
216
217 -spec build_forward_el(inbox_res()) -> exml:element().
218 build_forward_el(#{msg := Content, timestamp := Timestamp}) ->
219 683 Delay = build_delay_el(Timestamp),
220 683 #xmlel{name = <<"forwarded">>, attrs = [{<<"xmlns">>, ?NS_FORWARD}],
221 children = [Delay, Content]}.
222
223 -spec build_delay_el(Timestamp :: integer()) -> exml:element().
224 build_delay_el(Timestamp) ->
225 683 TS = calendar:system_time_to_rfc3339(Timestamp, [{offset, "Z"}, {unit, microsecond}]),
226 683 jlib:timestamp_to_xml(TS, undefined, undefined).
227
228 all_valid_boxes_for_query(HostType) ->
229 99 [<<"all">> | gen_mod:get_module_opt(HostType, mod_inbox, boxes)].
230
231 -spec list_single_form_field(Var :: binary(),
232 Default :: binary(),
233 Options :: [ Option | {Label, Value}]) -> exml:element() when
234 Option :: binary(), Label :: binary(), Value :: binary().
235 list_single_form_field(Var, Default, Options) ->
236 6 Value = form_field_value(Default),
237 6 #xmlel{
238 name = <<"field">>,
239 attrs = [{<<"var">>, Var}, {<<"type">>, <<"list-single">>}],
240 24 children = [Value | [ form_field_option(Option) || Option <- Options ]]
241 }.
242
243 -spec form_field_option(Option | {Label, Value}) -> exml:element() when
244 Option :: binary(), Label :: binary(), Value :: binary().
245 form_field_option({Label, Value}) ->
246 24 #xmlel{
247 name = <<"option">>,
248 attrs = [{<<"label">>, Label}],
249 children = [form_field_value(Value)]
250 };
251 form_field_option(Option) ->
252 20 form_field_option({Option, Option}).
253
254 -spec form_field_value(Value :: binary()) -> exml:element().
255 form_field_value(Value) ->
256 30 #xmlel{name = <<"value">>, children = [#xmlcdata{content = Value}]}.
257
258 -spec calculate_ts_from(integer(), non_neg_integer()) -> integer().
259 calculate_ts_from(Now, Days) ->
260 112 DaysInMicroSeconds = 86400000000 * Days, % 8.64e+10 microseconds in a day
261 112 Now - DaysInMicroSeconds.
Line Hits Source