./ct_report/coverage/mam_iq.COVER.html

1 -module(mam_iq).
2
3 -export([action/1]).
4 -export([action_type/1]).
5 -export([form_to_lookup_params/5]).
6 -export([lookup_params_with_archive_details/4]).
7
8 -import(mod_mam_utils,
9 [maybe_microseconds/1,
10 get_one_of_path/2]).
11
12 -include("jlib.hrl").
13 -include("mongoose_rsm.hrl").
14
15 -type action() :: 'mam_get_prefs'
16 | 'mam_lookup_messages'
17 | 'mam_set_prefs'
18 | 'mam_set_message_form'
19 | 'mam_get_message_form'.
20
21 -type lookup_params() :: #{
22 archive_id => mod_mam:archive_id(),
23 owner_jid => jid:jid(),
24 caller_jid => jid:jid(),
25 rsm => jlib:rsm_in() | undefined,
26 max_result_limit => non_neg_integer(),
27 %% Contains page size value provided by client or enforced by server.
28 %% It's a final value used by backend DB modules.
29 page_size => non_neg_integer(),
30 ordering_direction => backward | forward,
31 %% unix_timestamp() is in microseconds
32 now => mod_mam:unix_timestamp(),
33 %% Filtering by date
34 start_ts => mod_mam:unix_timestamp() | undefined,
35 end_ts => mod_mam:unix_timestamp() | undefined,
36 %% Filtering by contact
37 with_jid => jid:jid() | undefined,
38 %% Filtering by body text
39 search_text => binary() | undefined,
40 %% Filtering Result Set based on message ids
41 borders => mod_mam:borders() | undefined,
42 %% Affects 'policy-violation' for a case when:
43 %% - user does not use forms to query archive
44 %% - user does not provide "set" element
45 %% see form_to_lookup_params for more info
46 limit_passed => boolean(),
47 %% Optimizations flags
48 %% see form_to_lookup_params for more info
49 is_simple => true | false,
50 %% Can have more fields, added in maybe_add_extra_lookup_params function
51 %% in runtime
52 atom() => _
53 }.
54
55 -export_type([action/0, lookup_params/0]).
56
57 -callback extra_lookup_params(jlib:iq(), lookup_params()) -> lookup_params().
58
59 -spec action(jlib:iq()) -> action().
60 action(IQ = #iq{xmlns = ?NS_MAM_04}) ->
61 1511 action_v04plus(IQ);
62 action(IQ = #iq{xmlns = ?NS_MAM_06}) ->
63 233 action_v04plus(IQ).
64
65 action_v04plus(#iq{type = Action, sub_el = #xmlel{name = Category}}) ->
66 1744 case {Action, Category} of
67 308 {set, <<"prefs">>} -> mam_set_prefs;
68 161 {get, <<"prefs">>} -> mam_get_prefs;
69 28 {get, <<"query">>} -> mam_get_message_form;
70 1247 {set, <<"query">>} -> mam_set_message_form
71 end.
72
73 -spec action_type(action()) -> 'get' | 'set'.
74
:-(
action_type(mam_get_prefs) -> get;
75
:-(
action_type(mam_set_prefs) -> set;
76
:-(
action_type(mam_lookup_messages) -> get;
77 374 action_type(mam_set_message_form) -> get;
78
:-(
action_type(mam_get_message_form) -> get.
79
80 %% @doc Convert id into internal format.
81 -spec fix_rsm('none' | jlib:rsm_in()) -> 'undefined' | jlib:rsm_in().
82 fix_rsm(none) ->
83 603 undefined;
84 fix_rsm(RSM=#rsm_in{direction = aft, id = <<>>}) ->
85 49 RSM#rsm_in{direction = undefined, id = undefined}; %% First page
86 fix_rsm(RSM=#rsm_in{direction = aft, id = undefined}) ->
87
:-(
RSM#rsm_in{direction = undefined}; %% First page
88 fix_rsm(RSM=#rsm_in{id = undefined}) ->
89 140 RSM;
90 fix_rsm(RSM=#rsm_in{id = <<>>}) ->
91 112 RSM#rsm_in{id = undefined};
92 fix_rsm(RSM=#rsm_in{id = BExtMessID}) when is_binary(BExtMessID) ->
93 329 MessID = mod_mam_utils:external_binary_to_mess_id(BExtMessID),
94 329 RSM#rsm_in{id = MessID}.
95
96 %% @doc This element's name is "limit". But it must be "max" according XEP-0313.
97 -spec elem_to_limit(any()) -> any().
98 elem_to_limit(QueryEl) ->
99 1233 get_one_of_path(QueryEl, [
100 [{element, <<"set">>}, {element, <<"max">>}, cdata],
101 [{element, <<"set">>}, {element, <<"limit">>}, cdata]
102 ]).
103
104
105 -spec form_to_start_microseconds(mongoose_data_forms:kv_map()) -> 'undefined' | non_neg_integer().
106 form_to_start_microseconds(#{<<"start">> := [V]}) ->
107 49 maybe_microseconds(V);
108 form_to_start_microseconds(#{}) ->
109 1184 undefined.
110
111
112 -spec form_to_end_microseconds(mongoose_data_forms:kv_map()) -> 'undefined' | non_neg_integer().
113 form_to_end_microseconds(#{<<"end">> := [V]}) ->
114 35 maybe_microseconds(V);
115 form_to_end_microseconds(#{}) ->
116 1198 undefined.
117
118 -spec form_to_with_jid(mongoose_data_forms:kv_map()) -> 'error' | 'undefined' | jid:jid().
119 form_to_with_jid(#{<<"with">> := [JID]}) ->
120 28 jid:from_binary(JID);
121 form_to_with_jid(#{}) ->
122 1205 undefined.
123
124 -spec form_to_lookup_params(jlib:iq(), integer(), integer(), undefined | module(), boolean()) ->
125 lookup_params().
126 form_to_lookup_params(#iq{sub_el = QueryEl} = IQ, MaxResultLimit, DefaultResultLimit, Module, EnforceSimple) ->
127 1233 Params0 = common_lookup_params(QueryEl, MaxResultLimit, DefaultResultLimit),
128 1233 KVs = query_to_map(QueryEl),
129 1233 Params = Params0#{
130 %% Filtering by date.
131 %% Start :: integer() | undefined
132 start_ts => form_to_start_microseconds(KVs),
133 end_ts => form_to_end_microseconds(KVs),
134 %% Filtering by contact.
135 with_jid => form_to_with_jid(KVs),
136 %% Filtering by text
137 search_text => mod_mam_utils:form_to_text(KVs),
138
139 borders => mod_mam_utils:form_borders_decode(KVs),
140 %% Whether or not the client query included a <set/> element,
141 %% the server MAY simply return its limited results.
142 %% So, disable 'policy-violation'.
143 limit_passed => true,
144 %% `is_simple' can contain:
145 %% - true - do not count records (useful during pagination, when we already
146 %% know how many messages we have from a previous query);
147 %% - false - count messages (slow, according XEP-0313);
148 is_simple => maybe_enforce_simple(KVs, EnforceSimple)},
149 1212 maybe_add_extra_lookup_params(Module, Params, IQ).
150
151 -spec query_to_map(exml:element()) -> mongoose_data_forms:kv_map().
152 query_to_map(QueryEl) ->
153 1233 case mongoose_data_forms:find_form(QueryEl) of
154 undefined ->
155 491 #{};
156 Form ->
157 742 #{kvs := KVs} = mongoose_data_forms:parse_form_fields(Form),
158 742 KVs
159 end.
160
161 -spec common_lookup_params(exml:element(), non_neg_integer(), non_neg_integer()) ->
162 lookup_params().
163 common_lookup_params(QueryEl, MaxResultLimit, DefaultResultLimit) ->
164 1233 RSM = fix_rsm(jlib:rsm_decode(QueryEl)),
165 1233 Limit = elem_to_limit(QueryEl),
166 1233 #{now => erlang:system_time(microsecond),
167 rsm => RSM,
168 max_result_limit => MaxResultLimit,
169 page_size => min(MaxResultLimit,
170 mod_mam_utils:maybe_integer(Limit, DefaultResultLimit)),
171 limit_passed => Limit =/= <<>>,
172 ordering_direction => ordering_direction(RSM)}.
173
174 -spec lookup_params_with_archive_details(lookup_params(), term(), jid:jid(), jid:jid()) ->
175 lookup_params().
176 lookup_params_with_archive_details(Params, ArcID, ArcJID, CallerJID) ->
177 1212 Params#{archive_id => ArcID,
178 owner_jid => ArcJID,
179 caller_jid => CallerJID}.
180
181 287 ordering_direction(#rsm_in{direction = before}) -> backward;
182 946 ordering_direction(_) -> forward.
183
184 maybe_add_extra_lookup_params(undefined, Params, _) ->
185 1212 Params;
186 maybe_add_extra_lookup_params(Module, Params, IQ) ->
187
:-(
Module:extra_lookup_params(IQ, Params).
188
189 maybe_enforce_simple(_, true) ->
190 7 true;
191 maybe_enforce_simple(KVs, _) ->
192 1205 mod_mam_utils:form_decode_optimizations(KVs).
Line Hits Source