1 |
|
%%%------------------------------------------------------------------- |
2 |
|
%%% @author Uvarov Michael <arcusfelis@gmail.com> |
3 |
|
%%% @copyright (C) 2013, Uvarov Michael |
4 |
|
%%% @doc RDBMS backend for Message Archive Management. |
5 |
|
%%% @end |
6 |
|
%%%------------------------------------------------------------------- |
7 |
|
-module(mod_mam_rdbms_arch). |
8 |
|
|
9 |
|
%% ---------------------------------------------------------------------- |
10 |
|
%% Exports |
11 |
|
|
12 |
|
%% gen_mod handlers |
13 |
|
-export([start/2, stop/1, hooks/1, supported_features/0]). |
14 |
|
|
15 |
|
%% MAM hook handlers |
16 |
|
-behaviour(ejabberd_gen_mam_archive). |
17 |
|
-behaviour(gen_mod). |
18 |
|
-behaviour(mongoose_module_metrics). |
19 |
|
|
20 |
|
-callback encode(term()) -> binary(). |
21 |
|
-callback decode(binary()) -> term(). |
22 |
|
|
23 |
|
-export([archive_size/3, |
24 |
|
archive_message/3, |
25 |
|
lookup_messages/3, |
26 |
|
remove_archive/3, |
27 |
|
remove_domain/3, |
28 |
|
get_mam_pm_gdpr_data/3]). |
29 |
|
|
30 |
|
%% Called from mod_mam_rdbms_async_pool_writer |
31 |
|
-export([prepare_message/2, retract_message/2, prepare_insert/2]). |
32 |
|
|
33 |
|
-type host_type() :: mongooseim:host_type(). |
34 |
|
|
35 |
|
%% ---------------------------------------------------------------------- |
36 |
|
%% Imports |
37 |
|
|
38 |
|
-include("mongoose.hrl"). |
39 |
|
-include("jlib.hrl"). |
40 |
|
-include("mongoose_mam.hrl"). |
41 |
|
|
42 |
|
%% ---------------------------------------------------------------------- |
43 |
|
%% Types |
44 |
|
|
45 |
|
-type env_vars() :: #{ |
46 |
|
host_type := host_type(), |
47 |
|
archive_jid := jid:jid(), |
48 |
|
table := atom(), |
49 |
|
index_hint_fn := fun((env_vars()) -> mam_lookup_sql:sql_part()), |
50 |
|
columns_sql_fn := fun((mam_lookup_sql:query_type()) -> mam_lookup_sql:sql_part()), |
51 |
|
column_to_id_fn := fun((mam_lookup_sql:column()) -> string()), |
52 |
|
lookup_fn := mam_lookup_sql:lookup_query_fn(), |
53 |
|
decode_row_fn := fun((Row :: tuple(), env_vars()) -> Decoded :: tuple()), |
54 |
|
has_message_retraction := boolean(), |
55 |
|
has_full_text_search := boolean(), |
56 |
|
db_jid_codec := module(), |
57 |
|
db_message_codec := module() |
58 |
|
}. |
59 |
|
|
60 |
|
-export_type([env_vars/0]). |
61 |
|
|
62 |
|
%% ---------------------------------------------------------------------- |
63 |
|
%% gen_mod callbacks |
64 |
|
%% Starting and stopping functions for users' archives |
65 |
|
|
66 |
|
-spec start(host_type(), gen_mod:module_opts()) -> ok. |
67 |
|
start(_HostType, Opts) -> |
68 |
1 |
register_prepared_queries(Opts), |
69 |
1 |
ok. |
70 |
|
|
71 |
|
-spec stop(host_type()) -> ok. |
72 |
|
stop(_HostType) -> |
73 |
:-( |
ok. |
74 |
|
|
75 |
|
-spec supported_features() -> [atom()]. |
76 |
|
supported_features() -> |
77 |
1 |
[dynamic_domains]. |
78 |
|
|
79 |
|
-spec get_mam_pm_gdpr_data(Acc, Params, Extra) -> {ok, Acc} when |
80 |
|
Acc :: ejabberd_gen_mam_archive:mam_pm_gdpr_data(), |
81 |
|
Params :: #{jid := jid:jid()}, |
82 |
|
Extra :: gen_hook:extra(). |
83 |
|
get_mam_pm_gdpr_data(Acc, |
84 |
|
#{jid := #jid{luser = LUser, lserver = LServer} = ArcJID}, |
85 |
|
#{host_type := HostType}) -> |
86 |
:-( |
case mod_mam_pm:archive_id(LServer, LUser) of |
87 |
|
undefined -> |
88 |
:-( |
{ok, Acc}; |
89 |
|
ArcID -> |
90 |
:-( |
Env = env_vars(HostType, ArcJID), |
91 |
:-( |
{selected, Rows} = extract_gdpr_messages(Env, ArcID), |
92 |
:-( |
{ok, [uniform_to_gdpr(row_to_uniform_format(Row, Env)) || Row <- Rows] ++ Acc} |
93 |
|
end. |
94 |
|
|
95 |
|
-spec uniform_to_gdpr(mod_mam:message_row()) -> tuple(). |
96 |
|
uniform_to_gdpr(#{id := MessID, jid := RemoteJID, packet := Packet}) -> |
97 |
:-( |
{integer_to_binary(MessID), jid:to_binary(RemoteJID), exml:to_binary(Packet)}. |
98 |
|
|
99 |
|
%% ---------------------------------------------------------------------- |
100 |
|
%% Add hooks for mod_mam_pm |
101 |
|
|
102 |
|
-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list(). |
103 |
|
hooks(HostType) -> |
104 |
|
case gen_mod:get_module_opt(HostType, ?MODULE, no_writer) of |
105 |
|
true -> |
106 |
:-( |
[]; |
107 |
|
false -> |
108 |
1 |
[{mam_archive_message, HostType, fun ?MODULE:archive_message/3, #{}, 50}] |
109 |
1 |
end ++ |
110 |
|
[{mam_archive_size, HostType, fun ?MODULE:archive_size/3, #{}, 50}, |
111 |
|
{mam_lookup_messages, HostType, fun ?MODULE:lookup_messages/3, #{}, 50}, |
112 |
|
{mam_remove_archive, HostType, fun ?MODULE:remove_archive/3, #{}, 50}, |
113 |
|
{get_mam_pm_gdpr_data, HostType, fun ?MODULE:get_mam_pm_gdpr_data/3, #{}, 50}, |
114 |
|
{remove_domain, HostType, fun ?MODULE:remove_domain/3, #{}, 50}]. |
115 |
|
|
116 |
|
%% ---------------------------------------------------------------------- |
117 |
|
%% SQL queries |
118 |
|
|
119 |
|
register_prepared_queries(Opts) -> |
120 |
1 |
prepare_insert(insert_mam_message, 1), |
121 |
1 |
mongoose_rdbms:prepare(mam_archive_remove, mam_message, [user_id], |
122 |
|
<<"DELETE FROM mam_message " |
123 |
|
"WHERE user_id = ?">>), |
124 |
|
|
125 |
|
%% Domain Removal |
126 |
1 |
prepare_remove_domain(Opts), |
127 |
|
|
128 |
1 |
mongoose_rdbms:prepare(mam_make_tombstone, mam_message, [message, user_id, id], |
129 |
|
<<"UPDATE mam_message SET message = ?, search_body = '' " |
130 |
|
"WHERE user_id = ? AND id = ?">>), |
131 |
1 |
{LimitSQL, LimitMSSQL} = rdbms_queries:get_db_specific_limits_binaries(1), |
132 |
1 |
mongoose_rdbms:prepare(mam_select_messages_to_retract_on_origin_id, mam_message, |
133 |
|
[user_id, remote_bare_jid, origin_id, direction], |
134 |
|
<<"SELECT ", LimitMSSQL/binary, |
135 |
|
" id, message FROM mam_message" |
136 |
|
" WHERE user_id = ? AND remote_bare_jid = ? " |
137 |
|
" AND origin_id = ? AND direction = ?" |
138 |
|
" ORDER BY id DESC ", LimitSQL/binary>>), |
139 |
1 |
mongoose_rdbms:prepare(mam_select_messages_to_retract_on_stanza_id, mam_message, |
140 |
|
[user_id, remote_bare_jid, id, direction], |
141 |
|
<<"SELECT ", LimitMSSQL/binary, |
142 |
|
" origin_id, message FROM mam_message" |
143 |
|
" WHERE user_id = ? AND remote_bare_jid = ? " |
144 |
|
" AND id = ? AND direction = ?" |
145 |
|
" ORDER BY id DESC ", LimitSQL/binary>>). |
146 |
|
|
147 |
|
prepare_remove_domain(#{delete_domain_limit := infinity}) -> |
148 |
1 |
mongoose_rdbms:prepare(mam_remove_domain, mam_message, ['mam_server_user.server'], |
149 |
|
<<"DELETE FROM mam_message " |
150 |
|
"WHERE user_id IN " |
151 |
|
"(SELECT id from mam_server_user WHERE server = ?)">>), |
152 |
1 |
mongoose_rdbms:prepare(mam_remove_domain_prefs, mam_config, ['mam_server_user.server'], |
153 |
|
<<"DELETE FROM mam_config " |
154 |
|
"WHERE user_id IN " |
155 |
|
"(SELECT id from mam_server_user WHERE server = ?)">>), |
156 |
1 |
mongoose_rdbms:prepare(mam_remove_domain_users, mam_server_user, [server], |
157 |
|
<<"DELETE FROM mam_server_user WHERE server = ?">>); |
158 |
|
prepare_remove_domain(#{delete_domain_limit := Limit}) -> |
159 |
:-( |
LimitSQL = case mongoose_rdbms:db_type() of |
160 |
:-( |
mssql -> throw(delete_domain_limit_not_supported_for_mssql); |
161 |
:-( |
_ -> {MaybeLimitSQL, _} = rdbms_queries:get_db_specific_limits_binaries(Limit), |
162 |
:-( |
MaybeLimitSQL |
163 |
|
end, |
164 |
:-( |
IdTable = <<"(SELECT * FROM ", |
165 |
|
"(SELECT msg.user_id, msg.id FROM mam_message msg", |
166 |
|
" INNER JOIN mam_server_user msu ON msu.id=msg.user_id", |
167 |
|
" WHERE msu.server = ? ", LimitSQL/binary, ") AS T)">>, |
168 |
:-( |
mongoose_rdbms:prepare(mam_incr_remove_domain, mam_message, ['mam_server_user.server'], |
169 |
|
<<"DELETE FROM mam_message WHERE (user_id, id) IN ", IdTable/binary>>), |
170 |
:-( |
CfgTable = <<"(SELECT * FROM ", |
171 |
|
"(SELECT cfg.user_id, cfg.remote_jid FROM mam_config cfg", |
172 |
|
" INNER JOIN mam_server_user msu ON msu.id=cfg.user_id", |
173 |
|
" WHERE msu.server = ? ", LimitSQL/binary, ") AS T)">>, |
174 |
:-( |
mongoose_rdbms:prepare(mam_incr_remove_domain_prefs, mam_config, ['mam_server_user.server'], |
175 |
|
<<"DELETE FROM mam_config " |
176 |
|
"WHERE (user_id, remote_jid) IN ", CfgTable/binary>>), |
177 |
:-( |
ServerTable = <<"(SELECT * FROM ", |
178 |
|
"(SELECT id FROM mam_server_user WHERE server = ? ", LimitSQL/binary, ") as t)">>, |
179 |
:-( |
mongoose_rdbms:prepare(mam_incr_remove_domain_users, mam_server_user, [server], |
180 |
|
<<"DELETE FROM mam_server_user WHERE id IN ", ServerTable/binary>>). |
181 |
|
|
182 |
|
|
183 |
|
%% ---------------------------------------------------------------------- |
184 |
|
%% Declarative logic |
185 |
|
|
186 |
|
db_mappings() -> |
187 |
|
%% One entry per the database field |
188 |
61 |
[#db_mapping{column = id, param = message_id, format = int}, |
189 |
|
#db_mapping{column = user_id, param = archive_id, format = int}, |
190 |
|
#db_mapping{column = remote_bare_jid, param = remote_jid, format = bare_jid}, |
191 |
|
#db_mapping{column = remote_resource, param = remote_jid, format = jid_resource}, |
192 |
|
#db_mapping{column = direction, param = direction, format = direction}, |
193 |
|
#db_mapping{column = from_jid, param = source_jid, format = jid}, |
194 |
|
#db_mapping{column = origin_id, param = origin_id, format = maybe_string}, |
195 |
|
#db_mapping{column = message, param = packet, format = xml}, |
196 |
|
#db_mapping{column = search_body, param = packet, format = search}, |
197 |
|
#db_mapping{column = is_groupchat, param = is_groupchat, format = bool}]. |
198 |
|
|
199 |
|
lookup_fields() -> |
200 |
|
%% Describe each possible filtering option |
201 |
12 |
[#lookup_field{op = equal, column = user_id, param = archive_id, required = true}, |
202 |
|
#lookup_field{op = ge, column = id, param = start_id}, |
203 |
|
#lookup_field{op = le, column = id, param = end_id}, |
204 |
|
#lookup_field{op = equal, column = remote_bare_jid, param = remote_bare_jid}, |
205 |
|
#lookup_field{op = equal, column = remote_resource, param = remote_resource}, |
206 |
|
#lookup_field{op = like, column = search_body, param = norm_search_text, value_maker = search_words}, |
207 |
|
#lookup_field{op = equal, column = is_groupchat, param = include_groupchat}, |
208 |
|
#lookup_field{op = equal, column = id, param = message_id}]. |
209 |
|
|
210 |
|
-spec env_vars(host_type(), jid:jid()) -> env_vars(). |
211 |
|
env_vars(HostType, ArcJID) -> |
212 |
|
%% Please, minimize the usage of the host_type field. |
213 |
|
%% It's only for passing into RDBMS. |
214 |
72 |
#{host_type => HostType, |
215 |
|
archive_jid => ArcJID, |
216 |
|
table => mam_message, |
217 |
|
index_hint_fn => fun index_hint_sql/1, |
218 |
|
columns_sql_fn => fun columns_sql/1, |
219 |
|
column_to_id_fn => fun column_to_id/1, |
220 |
|
lookup_fn => fun lookup_query/5, |
221 |
|
decode_row_fn => fun row_to_uniform_format/2, |
222 |
|
has_message_retraction => mod_mam_utils:has_message_retraction(mod_mam_pm, HostType), |
223 |
|
has_full_text_search => mod_mam_utils:has_full_text_search(mod_mam_pm, HostType), |
224 |
|
db_jid_codec => mod_mam_utils:db_jid_codec(HostType, ?MODULE), |
225 |
|
db_message_codec => mod_mam_utils:db_message_codec(HostType, ?MODULE)}. |
226 |
|
|
227 |
|
row_to_uniform_format(Row, Env) -> |
228 |
8 |
mam_decoder:decode_row(Row, Env). |
229 |
|
|
230 |
|
-spec index_hint_sql(env_vars()) -> string(). |
231 |
|
index_hint_sql(#{host_type := HostType}) -> |
232 |
1 |
case mongoose_rdbms:db_engine(HostType) of |
233 |
1 |
mysql -> "USE INDEX(PRIMARY, i_mam_message_rem) "; |
234 |
:-( |
_ -> "" |
235 |
|
end. |
236 |
|
|
237 |
1 |
columns_sql(lookup) -> "id, from_jid, message"; |
238 |
:-( |
columns_sql(count) -> "COUNT(*)". |
239 |
|
|
240 |
|
%% For each unique column in lookup_fields() |
241 |
:-( |
column_to_id(id) -> "i"; |
242 |
12 |
column_to_id(user_id) -> "u"; |
243 |
:-( |
column_to_id(remote_bare_jid) -> "b"; |
244 |
:-( |
column_to_id(remote_resource) -> "r"; |
245 |
:-( |
column_to_id(search_body) -> "s"; |
246 |
:-( |
column_to_id(is_groupchat) -> "g". |
247 |
|
|
248 |
|
column_names(Mappings) -> |
249 |
1 |
[Column || #db_mapping{column = Column} <- Mappings]. |
250 |
|
|
251 |
|
%% ---------------------------------------------------------------------- |
252 |
|
%% Options |
253 |
|
|
254 |
|
-spec get_retract_id(exml:element(), env_vars()) -> none | mod_mam_utils:retraction_id(). |
255 |
|
get_retract_id(Packet, #{has_message_retraction := Enabled}) -> |
256 |
60 |
mod_mam_utils:get_retract_id(Enabled, Packet). |
257 |
|
|
258 |
|
%% ---------------------------------------------------------------------- |
259 |
|
%% Internal functions and callbacks |
260 |
|
|
261 |
|
-spec archive_size(Acc, Params, Extra) -> {ok, Acc} when |
262 |
|
Acc :: integer(), |
263 |
|
Params :: #{archive_id := mod_mam:archive_id() | undefined, owner := jid:jid()}, |
264 |
|
Extra :: gen_hook:extra(). |
265 |
|
archive_size(Size, #{archive_id := ArcID, owner := ArcJID}, #{host_type := HostType}) when is_integer(Size) -> |
266 |
:-( |
Filter = [{equal, user_id, ArcID}], |
267 |
:-( |
Env = env_vars(HostType, ArcJID), |
268 |
:-( |
Result = lookup_query(count, Env, Filter, unordered, all), |
269 |
:-( |
{ok, mongoose_rdbms:selected_to_integer(Result)}. |
270 |
|
|
271 |
|
-spec archive_message(Acc, Params, Extra) -> {ok, Acc} when |
272 |
|
Acc :: ok, |
273 |
|
Params :: mod_mam:archive_message_params(), |
274 |
|
Extra :: gen_hook:extra(). |
275 |
|
archive_message(_Result, #{local_jid := ArcJID} = Params, #{host_type := HostType}) -> |
276 |
60 |
try |
277 |
60 |
assert_archive_id_provided(Params), |
278 |
60 |
Env = env_vars(HostType, ArcJID), |
279 |
60 |
do_archive_message(HostType, Params, Env), |
280 |
60 |
retract_message(HostType, Params, Env), |
281 |
60 |
{ok, ok} |
282 |
|
catch error:Reason:StackTrace -> |
283 |
:-( |
?LOG_ERROR(#{what => archive_message_failed, |
284 |
|
host_type => HostType, mam_params => Params, |
285 |
:-( |
reason => Reason, stacktrace => StackTrace}), |
286 |
:-( |
erlang:raise(error, Reason, StackTrace) |
287 |
|
end. |
288 |
|
|
289 |
|
do_archive_message(HostType, Params, Env) -> |
290 |
60 |
Row = mam_encoder:encode_message(Params, Env, db_mappings()), |
291 |
60 |
{updated, 1} = mongoose_rdbms:execute_successfully(HostType, insert_mam_message, Row). |
292 |
|
|
293 |
|
%% Retraction logic |
294 |
|
%% Called after inserting a new message |
295 |
|
-spec retract_message(host_type(), mod_mam:archive_message_params()) -> ok. |
296 |
|
retract_message(HostType, #{local_jid := ArcJID} = Params) -> |
297 |
:-( |
Env = env_vars(HostType, ArcJID), |
298 |
:-( |
retract_message(HostType, Params, Env). |
299 |
|
|
300 |
|
-spec retract_message(host_type(), mod_mam:archive_message_params(), env_vars()) -> ok. |
301 |
|
retract_message(HostType, #{archive_id := ArcID, remote_jid := RemJID, |
302 |
|
direction := Dir, packet := Packet} = Params, Env) -> |
303 |
60 |
case get_retract_id(Packet, Env) of |
304 |
60 |
none -> ok; |
305 |
|
RetractionId -> |
306 |
:-( |
Info = get_retraction_info(HostType, ArcID, RemJID, RetractionId, Dir, Env), |
307 |
:-( |
make_tombstone(HostType, ArcID, RetractionId, Info, Params, Env) |
308 |
|
end. |
309 |
|
|
310 |
|
get_retraction_info(HostType, ArcID, RemJID, RetractionId, Dir, Env) -> |
311 |
|
%% Code style notice: |
312 |
|
%% - Add Ext prefix for all externally encoded data |
313 |
|
%% (in cases, when we usually add Bin, B, S Esc prefixes) |
314 |
:-( |
ExtBareRemJID = mam_encoder:encode_jid(jid:to_bare(RemJID), Env), |
315 |
:-( |
ExtDir = mam_encoder:encode_direction(Dir), |
316 |
:-( |
{selected, Rows} = execute_select_messages_to_retract( |
317 |
|
HostType, ArcID, ExtBareRemJID, RetractionId, ExtDir), |
318 |
:-( |
mam_decoder:decode_retraction_info(Env, Rows, RetractionId). |
319 |
|
|
320 |
|
make_tombstone(_HostType, ArcID, RetractionId, skip, _Params, _Env) -> |
321 |
:-( |
?LOG_INFO(#{what => make_tombstone_failed, |
322 |
|
text => <<"Message to retract was not found">>, |
323 |
:-( |
user_id => ArcID, retraction_context => RetractionId}); |
324 |
|
make_tombstone(HostType, ArcID, _RetractionId, |
325 |
|
RetractionInfo = #{message_id := MessID}, Params, |
326 |
|
#{archive_jid := ArcJID} = Env) -> |
327 |
:-( |
RetractionInfo1 = mongoose_hooks:mam_retraction(HostType, RetractionInfo, Params), |
328 |
:-( |
Tombstone = mod_mam_utils:tombstone(RetractionInfo1, ArcJID), |
329 |
:-( |
TombstoneData = mam_encoder:encode_packet(Tombstone, Env), |
330 |
:-( |
execute_make_tombstone(HostType, TombstoneData, ArcID, MessID). |
331 |
|
|
332 |
|
execute_select_messages_to_retract(HostType, ArcID, BareRemJID, {origin_id, OriginID}, Dir) -> |
333 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_select_messages_to_retract_on_origin_id, |
334 |
|
[ArcID, BareRemJID, OriginID, Dir]); |
335 |
|
execute_select_messages_to_retract(HostType, ArcID, BareRemJID, {stanza_id, BinStanzaId}, Dir) -> |
336 |
:-( |
StanzaId = mod_mam_utils:external_binary_to_mess_id(BinStanzaId), |
337 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_select_messages_to_retract_on_stanza_id, |
338 |
|
[ArcID, BareRemJID, StanzaId, Dir]). |
339 |
|
|
340 |
|
execute_make_tombstone(HostType, TombstoneData, ArcID, MessID) -> |
341 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_make_tombstone, |
342 |
|
[TombstoneData, ArcID, MessID]). |
343 |
|
|
344 |
|
%% Insert logic |
345 |
|
-spec prepare_message(host_type(), mod_mam:archive_message_params()) -> list(). |
346 |
|
prepare_message(HostType, Params = #{local_jid := ArcJID}) -> |
347 |
:-( |
Env = env_vars(HostType, ArcJID), |
348 |
:-( |
mam_encoder:encode_message(Params, Env, db_mappings()). |
349 |
|
|
350 |
|
-spec prepare_insert(Name :: atom(), NumRows :: pos_integer()) -> ok. |
351 |
|
prepare_insert(Name, NumRows) -> |
352 |
1 |
Table = mam_message, |
353 |
1 |
Fields = column_names(db_mappings()), |
354 |
1 |
{Query, Fields2} = rdbms_queries:create_bulk_insert_query(Table, Fields, NumRows), |
355 |
1 |
mongoose_rdbms:prepare(Name, Table, Fields2, Query), |
356 |
1 |
ok. |
357 |
|
|
358 |
|
%% Removal logic |
359 |
|
-spec remove_archive(Acc, Params, Extra) -> {ok, Acc} when |
360 |
|
Acc :: term(), |
361 |
|
Params :: #{archive_id := mod_mam:archive_id() | undefined, owner := jid:jid()}, |
362 |
|
Extra :: gen_hook:extra(). |
363 |
|
remove_archive(Acc, #{archive_id := ArcID}, #{host_type := HostType}) -> |
364 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_archive_remove, [ArcID]), |
365 |
:-( |
{ok, Acc}. |
366 |
|
|
367 |
|
-spec remove_domain(Acc, Params, Extra) -> {ok | stop, Acc} when |
368 |
|
Acc :: mongoose_domain_api:remove_domain_acc(), |
369 |
|
Params :: map(), |
370 |
|
Extra :: gen_hook:extra(). |
371 |
|
remove_domain(Acc, #{domain := Domain}, #{host_type := HostType}) -> |
372 |
:-( |
F = fun() -> |
373 |
:-( |
case gen_mod:get_module_opt(HostType, ?MODULE, delete_domain_limit) of |
374 |
:-( |
infinity -> remove_domain_all(HostType, Domain); |
375 |
:-( |
Limit -> remove_domain_batch(HostType, Domain, Limit) |
376 |
|
end, |
377 |
:-( |
Acc |
378 |
|
end, |
379 |
:-( |
mongoose_domain_api:remove_domain_wrapper(Acc, F, ?MODULE). |
380 |
|
|
381 |
|
-spec remove_domain_all(host_type(), jid:lserver()) -> any(). |
382 |
|
remove_domain_all(HostType, Domain) -> |
383 |
:-( |
{atomic, _} = mongoose_rdbms:sql_transaction(HostType, fun() -> |
384 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_remove_domain, [Domain]), |
385 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_remove_domain_prefs, [Domain]), |
386 |
:-( |
mongoose_rdbms:execute_successfully(HostType, mam_remove_domain_users, [Domain]) |
387 |
|
end). |
388 |
|
|
389 |
|
-spec remove_domain_batch(host_type(), jid:lserver(), non_neg_integer()) -> any(). |
390 |
|
remove_domain_batch(HostType, Domain, Limit) -> |
391 |
:-( |
DeleteQueries = [mam_incr_remove_domain, mam_incr_remove_domain_prefs, mam_incr_remove_domain_users], |
392 |
:-( |
TotalDeleted = mod_mam_utils:incremental_delete_domain(HostType, Domain, Limit, DeleteQueries, 0), |
393 |
:-( |
?LOG_INFO(#{what => mam_domain_removal_completed, total_records_deleted => TotalDeleted, |
394 |
:-( |
domain => Domain, host_type => HostType}). |
395 |
|
|
396 |
|
%% GDPR logic |
397 |
|
extract_gdpr_messages(Env, ArcID) -> |
398 |
:-( |
Filters = [{equal, user_id, ArcID}], |
399 |
:-( |
lookup_query(lookup, Env, Filters, asc, all). |
400 |
|
|
401 |
|
%% Lookup logic |
402 |
|
-spec lookup_messages(Acc, Params, Extra) -> {ok, Acc} when |
403 |
|
Acc :: {ok, mod_mam:lookup_result()}, |
404 |
|
Params :: mam_iq:lookup_params(), |
405 |
|
Extra :: gen_hook:extra(). |
406 |
|
lookup_messages(_Result, #{owner_jid := ArcJID} = Params, #{host_type := HostType}) -> |
407 |
12 |
Env = env_vars(HostType, ArcJID), |
408 |
12 |
ExdParams = mam_encoder:extend_lookup_params(Params, Env), |
409 |
12 |
Filter = mam_filter:produce_filter(ExdParams, lookup_fields()), |
410 |
12 |
{ok, mam_lookup:lookup(Env, Filter, ExdParams)}. |
411 |
|
|
412 |
|
lookup_query(QueryType, Env, Filters, Order, OffsetLimit) -> |
413 |
12 |
mam_lookup_sql:lookup_query(QueryType, Env, Filters, Order, OffsetLimit). |
414 |
|
|
415 |
|
assert_archive_id_provided(#{archive_id := ArcID}) when is_integer(ArcID) -> |
416 |
60 |
ok. |