./ct_report/coverage/mam_iq.COVER.html

1 -module(mam_iq).
2
3 -export([action/1]).
4 -export([action_type/1]).
5
6 -export([fix_rsm/1]).
7 -export([elem_to_start_microseconds/1]).
8 -export([elem_to_end_microseconds/1]).
9 -export([elem_to_with_jid/1]).
10 -export([elem_to_limit/1]).
11 -export([query_to_lookup_params/4]).
12
13 -export([form_to_start_microseconds/1]).
14 -export([form_to_end_microseconds/1]).
15 -export([form_to_with_jid/1]).
16 -export([form_to_lookup_params/4]).
17
18 -export([lookup_params_with_archive_details/4]).
19
20 -ignore_xref([behaviour_info/1, elem_to_end_microseconds/1, elem_to_limit/1,
21 elem_to_start_microseconds/1, elem_to_with_jid/1, fix_rsm/1,
22 form_to_end_microseconds/1, form_to_start_microseconds/1,
23 form_to_with_jid/1, query_to_lookup_params/4]).
24
25 -import(mod_mam_utils,
26 [maybe_microseconds/1,
27 get_one_of_path/2,
28 form_field_value_s/2]).
29
30 -include("jlib.hrl").
31 -include("mongoose_rsm.hrl").
32
33 -type action() :: 'mam_get_prefs'
34 | 'mam_lookup_messages'
35 | 'mam_set_prefs'
36 | 'mam_set_message_form'
37 | 'mam_get_message_form'.
38
39 -type lookup_params() :: #{
40 archive_id => mod_mam:archive_id(),
41 owner_jid => jid:jid(),
42 caller_jid => jid:jid(),
43 rsm => jlib:rsm_in() | undefined,
44 max_result_limit => non_neg_integer(),
45 %% Contains page size value provided by client or enforced by server.
46 %% It's a final value used by backend DB modules.
47 page_size => non_neg_integer(),
48 ordering_direction => backward | forward,
49 %% unix_timestamp() is in microseconds
50 now => mod_mam:unix_timestamp(),
51 %% Filtering by date
52 start_ts => mod_mam:unix_timestamp() | undefined,
53 end_ts => mod_mam:unix_timestamp() | undefined,
54 %% Filtering by contact
55 with_jid => jid:jid() | undefined,
56 %% Filtering by body text
57 search_text => binary() | undefined,
58 %% Filtering Result Set based on message ids
59 borders => mod_mam:borders() | undefined,
60 %% Affects 'policy-violation' for a case when:
61 %% - user does not use forms to query archive
62 %% - user does not provide "set" element
63 %% see form_to_lookup_params for more info
64 limit_passed => boolean(),
65 %% Optimizations flags
66 %% see form_to_lookup_params for more info
67 is_simple => true | false | opt_count,
68 %% Can have more fields, added in maybe_add_extra_lookup_params function
69 %% in runtime
70 atom() => _
71 }.
72
73 -export_type([action/0]).
74 -export_type([lookup_params/0]).
75
76 -callback extra_lookup_params(jlib:iq(), lookup_params()) -> lookup_params().
77
78 -spec action(jlib:iq()) -> action().
79 action(IQ = #iq{xmlns = ?NS_MAM_04}) ->
80
:-(
action_v04plus(IQ);
81 action(IQ = #iq{xmlns = ?NS_MAM_06}) ->
82
:-(
action_v04plus(IQ).
83
84 action_v04plus(#iq{type = Action, sub_el = #xmlel{name = Category}}) ->
85
:-(
case {Action, Category} of
86
:-(
{set, <<"prefs">>} -> mam_set_prefs;
87
:-(
{get, <<"prefs">>} -> mam_get_prefs;
88
:-(
{get, <<"query">>} -> mam_get_message_form;
89
:-(
{set, <<"query">>} -> mam_set_message_form
90 end.
91
92 -spec action_type(action()) -> 'get' | 'set'.
93
:-(
action_type(mam_get_prefs) -> get;
94
:-(
action_type(mam_set_prefs) -> set;
95
:-(
action_type(mam_lookup_messages) -> get;
96
:-(
action_type(mam_set_message_form) -> get;
97
:-(
action_type(mam_get_message_form) -> get.
98
99 %% @doc Convert id into internal format.
100 -spec fix_rsm('none' | jlib:rsm_in()) -> 'undefined' | jlib:rsm_in().
101 fix_rsm(none) ->
102
:-(
undefined;
103 fix_rsm(RSM=#rsm_in{direction = aft, id = <<>>}) ->
104
:-(
RSM#rsm_in{direction = undefined, id = undefined}; %% First page
105 fix_rsm(RSM=#rsm_in{direction = aft, id = undefined}) ->
106
:-(
RSM#rsm_in{direction = undefined}; %% First page
107 fix_rsm(RSM=#rsm_in{id = undefined}) ->
108
:-(
RSM;
109 fix_rsm(RSM=#rsm_in{id = <<>>}) ->
110
:-(
RSM#rsm_in{id = undefined};
111 fix_rsm(RSM=#rsm_in{id = BExtMessID}) when is_binary(BExtMessID) ->
112
:-(
MessID = mod_mam_utils:external_binary_to_mess_id(BExtMessID),
113
:-(
RSM#rsm_in{id = MessID}.
114
115
116 -spec elem_to_start_microseconds(exml:element()) -> 'undefined' | non_neg_integer().
117 elem_to_start_microseconds(El) ->
118
:-(
maybe_microseconds(exml_query:path(El, [{element, <<"start">>}, cdata], <<>>)).
119
120
121 -spec elem_to_end_microseconds(exml:element()) -> 'undefined' | non_neg_integer().
122 elem_to_end_microseconds(El) ->
123
:-(
maybe_microseconds(exml_query:path(El, [{element, <<"end">>}, cdata], <<>>)).
124
125
126 -spec elem_to_with_jid(exml:element()) -> 'error' | 'undefined' | jid:jid().
127 elem_to_with_jid(El) ->
128
:-(
maybe_jid(exml_query:path(El, [{element, <<"with">>}, cdata], <<>>)).
129
130 %% @doc This element's name is "limit". But it must be "max" according XEP-0313.
131 -spec elem_to_limit(any()) -> any().
132 elem_to_limit(QueryEl) ->
133
:-(
get_one_of_path(QueryEl, [
134 [{element, <<"set">>}, {element, <<"max">>}, cdata],
135 [{element, <<"set">>}, {element, <<"limit">>}, cdata]
136 ]).
137
138
139 -spec form_to_start_microseconds(_) -> 'undefined' | non_neg_integer().
140 form_to_start_microseconds(El) ->
141
:-(
maybe_microseconds(form_field_value_s(El, <<"start">>)).
142
143
144 -spec form_to_end_microseconds(_) -> 'undefined' | non_neg_integer().
145 form_to_end_microseconds(El) ->
146
:-(
maybe_microseconds(form_field_value_s(El, <<"end">>)).
147
148
149 -spec form_to_with_jid(exml:element()) -> 'error' | 'undefined' | jid:jid().
150 form_to_with_jid(El) ->
151
:-(
maybe_jid(form_field_value_s(El, <<"with">>)).
152
153
154 -spec maybe_jid(binary()) -> 'error' | 'undefined' | jid:jid().
155 maybe_jid(<<>>) ->
156
:-(
undefined;
157 maybe_jid(JID) when is_binary(JID) ->
158
:-(
jid:from_binary(JID).
159
160 -spec query_to_lookup_params(jlib:iq(), integer(), integer(), undefined | module()) ->
161 lookup_params().
162 query_to_lookup_params(#iq{sub_el = QueryEl} = IQ, MaxResultLimit, DefaultResultLimit, Module) ->
163
:-(
Params0 = common_lookup_params(QueryEl, MaxResultLimit, DefaultResultLimit),
164
:-(
Params = Params0#{
165 %% Filtering by date.
166 %% Start :: integer() | undefined
167 start_ts => elem_to_start_microseconds(QueryEl),
168 end_ts => elem_to_end_microseconds(QueryEl),
169 %% Filtering by contact.
170 search_text => undefined,
171 with_jid => elem_to_with_jid(QueryEl),
172 borders => mod_mam_utils:borders_decode(QueryEl),
173 is_simple => mod_mam_utils:decode_optimizations(QueryEl)},
174
175
:-(
maybe_add_extra_lookup_params(Module, Params, IQ).
176
177
178 -spec form_to_lookup_params(jlib:iq(), integer(), integer(), undefined | module()) ->
179 lookup_params().
180 form_to_lookup_params(#iq{sub_el = QueryEl} = IQ, MaxResultLimit, DefaultResultLimit, Module) ->
181
:-(
Params0 = common_lookup_params(QueryEl, MaxResultLimit, DefaultResultLimit),
182
:-(
Params = Params0#{
183 %% Filtering by date.
184 %% Start :: integer() | undefined
185 start_ts => form_to_start_microseconds(QueryEl),
186 end_ts => form_to_end_microseconds(QueryEl),
187 %% Filtering by contact.
188 with_jid => form_to_with_jid(QueryEl),
189 %% Filtering by text
190 search_text => mod_mam_utils:form_to_text(QueryEl),
191
192 borders => mod_mam_utils:form_borders_decode(QueryEl),
193 %% Whether or not the client query included a <set/> element,
194 %% the server MAY simply return its limited results.
195 %% So, disable 'policy-violation'.
196 limit_passed => true,
197 %% `is_simple' can contain three values:
198 %% - true - do not count records (useful during pagination, when we already
199 %% know how many messages we have from a previous query);
200 %% - false - count messages (slow, according XEP-0313);
201 %% - opt_count - count messages (same as false, fast for small result sets)
202 %%
203 %% The difference between false and opt_count is that with IsSimple=false we count
204 %% messages first and then extract a messages on a page (if count is not zero).
205 %% If IsSimple=opt_count we extract a page and then calculate messages (if required).
206 %% `opt_count' can be passed inside an IQ.
207 %% Same for mod_mam_muc.
208 is_simple => mod_mam_utils:form_decode_optimizations(QueryEl)},
209
:-(
maybe_add_extra_lookup_params(Module, Params, IQ).
210
211 -spec common_lookup_params(exml:element(), non_neg_integer(), non_neg_integer()) ->
212 lookup_params().
213 common_lookup_params(QueryEl, MaxResultLimit, DefaultResultLimit) ->
214
:-(
RSM = fix_rsm(jlib:rsm_decode(QueryEl)),
215
:-(
Limit = elem_to_limit(QueryEl),
216
:-(
#{now => erlang:system_time(microsecond),
217 rsm => RSM,
218 max_result_limit => MaxResultLimit,
219 page_size => min(MaxResultLimit,
220 mod_mam_utils:maybe_integer(Limit, DefaultResultLimit)),
221 limit_passed => Limit =/= <<>>,
222 ordering_direction => ordering_direction(RSM)}.
223
224 -spec lookup_params_with_archive_details(lookup_params(), term(), jid:jid(), jid:jid()) ->
225 lookup_params().
226 lookup_params_with_archive_details(Params, ArcID, ArcJID, CallerJID) ->
227
:-(
Params#{archive_id => ArcID,
228 owner_jid => ArcJID,
229 caller_jid => CallerJID}.
230
231
:-(
ordering_direction(#rsm_in{direction = before}) -> backward;
232
:-(
ordering_direction(_) -> forward.
233
234 maybe_add_extra_lookup_params(undefined, Params, _) ->
235
:-(
Params;
236 maybe_add_extra_lookup_params(Module, Params, IQ) ->
237
:-(
Module:extra_lookup_params(IQ, Params).
238
Line Hits Source