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