./ct_report/coverage/mod_muc_light_db_rdbms.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : mod_muc_light_db_rdbms.erl
3 %%% Author : Piotr Nosek <piotr.nosek@erlang-solutions.com>
4 %%% Purpose : RDBMS backend for mod_muc_light
5 %%% Created : 24 Nov 2016 by Piotr Nosek <piotr.nosek@erlang-solutions.com>
6 %%%
7 %%% This program is free software; you can redistribute it and/or
8 %%% modify it under the terms of the GNU General Public License as
9 %%% published by the Free Software Foundation; either version 2 of the
10 %%% License, or (at your option) any later version.
11 %%%
12 %%% This program is distributed in the hope that it will be useful,
13 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
14 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 %%% General Public License for more details.
16 %%%
17 %%% You should have received a copy of the GNU General Public License
18 %%% along with this program; if not, write to the Free Software
19 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 %%%
21 %%%----------------------------------------------------------------------
22
23 -module(mod_muc_light_db_rdbms).
24 -author('piotr.nosek@erlang-solutions.com').
25
26 -behaviour(mod_muc_light_db_backend).
27
28 %% API
29 -export([
30 start/2,
31 stop/1,
32 create_room/5,
33 destroy_room/2,
34 room_exists/2,
35 get_user_rooms/3,
36 get_user_rooms_count/2,
37 remove_user/3,
38 remove_domain/3,
39 get_config/2,
40 set_config/4,
41 get_blocking/3,
42 get_blocking/4,
43 set_blocking/4,
44 get_aff_users/2,
45 modify_aff_users/5,
46 get_info/2
47 ]).
48
49 %% Extra API for testing
50 -export([force_clear/0,
51 select_room_id/3,
52 select_affs_by_room_id/2,
53 select_config_by_room_id/2
54 ]).
55
56 -ignore_xref([force_clear/0,
57 select_room_id/3,
58 select_affs_by_room_id/2,
59 select_config_by_room_id/2]).
60
61 -type room_id() :: non_neg_integer().
62
63 -include("mongoose.hrl").
64 -include("mod_muc_light.hrl").
65
66 %%====================================================================
67 %% API
68 %%====================================================================
69
70 %% ------------------------ Backend start/stop ------------------------
71
72 -spec start(HostType :: mongooseim:host_type(), gen_mod:module_opts()) -> ok.
73 start(_HostType, _) ->
74
:-(
prepare_queries(),
75
:-(
ok.
76
77 -spec stop(HostType :: mongooseim:host_type()) -> ok.
78 stop(_HostType) ->
79
:-(
ok.
80
81 %% ------------------------ SQL -------------------------------------------
82
83 prepare_queries() ->
84
:-(
prepare_cleaning_queries(),
85
:-(
prepare_room_queries(),
86
:-(
prepare_affiliation_queries(),
87
:-(
prepare_config_queries(),
88
:-(
prepare_blocking_queries(),
89
:-(
prepare_domain_removal_queries(),
90
:-(
ok.
91
92 prepare_cleaning_queries() ->
93
:-(
mongoose_rdbms:prepare(muc_light_config_delete_all, muc_light_config, [],
94 <<"DELETE FROM muc_light_config">>),
95
:-(
mongoose_rdbms:prepare(muc_light_occupants_delete_all, muc_light_occupants, [],
96 <<"DELETE FROM muc_light_occupants">>),
97
:-(
mongoose_rdbms:prepare(muc_light_rooms_delete_all, muc_light_rooms, [],
98 <<"DELETE FROM muc_light_rooms">>),
99
:-(
mongoose_rdbms:prepare(muc_light_blocking_delete_all, muc_light_blocking, [],
100 <<"DELETE FROM muc_light_blocking">>),
101
:-(
ok.
102
103 prepare_room_queries() ->
104 %% Returns maximum 1 record
105
:-(
mongoose_rdbms:prepare(muc_light_select_room_id, muc_light_rooms,
106 [luser, lserver],
107 <<"SELECT id FROM muc_light_rooms "
108 "WHERE luser = ? AND lserver = ?">>),
109
:-(
mongoose_rdbms:prepare(muc_light_select_room_id_and_version, muc_light_rooms,
110 [luser, lserver],
111 <<"SELECT id, version FROM muc_light_rooms "
112 "WHERE luser = ? AND lserver = ?">>),
113
:-(
mongoose_rdbms:prepare(muc_light_insert_room, muc_light_rooms,
114 [luser, lserver, version],
115 <<"INSERT INTO muc_light_rooms (luser, lserver, version)"
116 " VALUES (?, ?, ?)">>),
117
:-(
mongoose_rdbms:prepare(muc_light_update_room_version, muc_light_rooms,
118 [luser, lserver, version],
119 <<"UPDATE muc_light_rooms SET version = ? "
120 " WHERE luser = ? AND lserver = ?">>),
121
:-(
mongoose_rdbms:prepare(muc_light_delete_room, muc_light_rooms,
122 [luser, lserver],
123 <<"DELETE FROM muc_light_rooms"
124 " WHERE luser = ? AND lserver = ?">>),
125 %% These queries use multiple tables
126
:-(
mongoose_rdbms:prepare(muc_light_select_user_rooms, muc_light_occupants,
127 [luser, lserver],
128 <<"SELECT r.luser, r.lserver "
129 " FROM muc_light_occupants AS o "
130 " INNER JOIN muc_light_rooms AS r ON o.room_id = r.id"
131 " WHERE o.luser = ? AND o.lserver = ?">>),
132
:-(
mongoose_rdbms:prepare(muc_light_select_user_rooms_count, muc_light_occupants,
133 [luser, lserver],
134 <<"SELECT count(*) "
135 " FROM muc_light_occupants AS o "
136 " INNER JOIN muc_light_rooms AS r ON o.room_id = r.id"
137 " WHERE o.luser = ? AND o.lserver = ?">>),
138
:-(
ok.
139
140 prepare_affiliation_queries() ->
141 %% This query uses multiple tables
142 %% Also returns a room version
143
:-(
mongoose_rdbms:prepare(muc_light_select_affs_by_us, muc_light_rooms,
144 [luser, lserver],
145 <<"SELECT version, o.luser, o.lserver, aff"
146 " FROM muc_light_rooms AS r "
147 " LEFT OUTER JOIN muc_light_occupants AS o ON r.id = o.room_id"
148 " WHERE r.luser = ? AND r.lserver = ?">>),
149
:-(
mongoose_rdbms:prepare(muc_light_select_affs_by_room_id, muc_light_occupants,
150 [room_id],
151 <<"SELECT luser, lserver, aff "
152 "FROM muc_light_occupants WHERE room_id = ?">>),
153
:-(
mongoose_rdbms:prepare(muc_light_insert_aff, muc_light_occupants,
154 [room_id, luser, lserver, aff],
155 <<"INSERT INTO muc_light_occupants"
156 " (room_id, luser, lserver, aff)"
157 " VALUES(?, ?, ?, ?)">>),
158
:-(
mongoose_rdbms:prepare(muc_light_update_aff, muc_light_occupants,
159 [aff, room_id, luser, lserver],
160 <<"UPDATE muc_light_occupants SET aff = ? "
161 "WHERE room_id = ? AND luser = ? AND lserver = ?">>),
162
:-(
mongoose_rdbms:prepare(muc_light_delete_affs, muc_light_occupants,
163 [room_id],
164 <<"DELETE FROM muc_light_occupants WHERE room_id = ?">>),
165
:-(
mongoose_rdbms:prepare(muc_light_delete_aff, muc_light_occupants,
166 [room_id, luser, lserver],
167 <<"DELETE FROM muc_light_occupants "
168 "WHERE room_id = ? AND luser = ? AND lserver = ?">>),
169
:-(
ok.
170
171 prepare_config_queries() ->
172
:-(
mongoose_rdbms:prepare(muc_light_select_config_by_room_id, muc_light_config,
173 [room_id],
174 <<"SELECT opt, val FROM muc_light_config WHERE room_id = ?">>),
175 %% This query uses multiple tables
176
:-(
mongoose_rdbms:prepare(muc_light_select_config_by_us, muc_light_rooms,
177 [luser, lserver],
178 <<"SELECT version, opt, val "
179 "FROM muc_light_rooms AS r "
180 "LEFT OUTER JOIN muc_light_config AS c ON r.id = c.room_id "
181 "WHERE r.luser = ? AND r.lserver = ?">>),
182
:-(
mongoose_rdbms:prepare(muc_light_insert_config, muc_light_config,
183 [room_id, opt, val],
184 <<"INSERT INTO muc_light_config (room_id, opt, val)"
185 " VALUES(?, ?, ?)">>),
186
:-(
mongoose_rdbms:prepare(muc_light_update_config, muc_light_config,
187 [val, room_id, opt],
188 <<"UPDATE muc_light_config SET val = ? "
189 "WHERE room_id = ? AND opt = ?">>),
190
:-(
mongoose_rdbms:prepare(muc_light_delete_config, muc_light_config,
191 [room_id],
192 <<"DELETE FROM muc_light_config WHERE room_id = ?">>),
193
:-(
ok.
194
195 prepare_blocking_queries() ->
196
:-(
mongoose_rdbms:prepare(muc_light_select_blocking, muc_light_blocking,
197 [luser, lserver],
198 <<"SELECT what, who FROM muc_light_blocking "
199 "WHERE luser = ? AND lserver = ?">>),
200
:-(
mongoose_rdbms:prepare(muc_light_select_blocking_cnt, muc_light_blocking,
201 [luser, lserver, what, who],
202 <<"SELECT COUNT(*) FROM muc_light_blocking "
203 "WHERE luser = ? AND lserver = ? AND "
204 "what = ? AND who = ?">>),
205
:-(
mongoose_rdbms:prepare(muc_light_select_blocking_cnt2, muc_light_blocking,
206 [luser, lserver, what, who, what, who],
207 <<"SELECT COUNT(*) FROM muc_light_blocking "
208 "WHERE luser = ? AND lserver = ? AND "
209 "((what = ? AND who = ?) OR (what = ? AND who = ?))">>),
210
:-(
mongoose_rdbms:prepare(muc_light_insert_blocking, muc_light_blocking,
211 [luser, lserver, what, who],
212 <<"INSERT INTO muc_light_blocking"
213 " (luser, lserver, what, who)"
214 " VALUES (?, ?, ?, ?)">>),
215
:-(
mongoose_rdbms:prepare(muc_light_delete_blocking1, muc_light_blocking,
216 [luser, lserver, what, who],
217 <<"DELETE FROM muc_light_blocking "
218 "WHERE luser = ? AND lserver = ? AND what = ? AND who = ?">>),
219
:-(
mongoose_rdbms:prepare(muc_light_delete_blocking, muc_light_blocking,
220 [luser, lserver],
221 <<"DELETE FROM muc_light_blocking"
222 " WHERE luser = ? AND lserver = ?">>),
223
:-(
ok.
224
225 prepare_domain_removal_queries() ->
226 %% RoomS argument
227
:-(
mongoose_rdbms:prepare(muc_light_occupants_remove_room_domain, muc_light_occupants,
228 ['muc_light_rooms.lserver'],
229 <<"DELETE FROM muc_light_occupants WHERE room_id IN "
230 "(SELECT id FROM muc_light_rooms WHERE lserver = ?)">>),
231 %% User's LServer argument
232
:-(
mongoose_rdbms:prepare(muc_light_occupants_remove_user_domain, muc_light_occupants,
233 [lserver],
234 <<"DELETE FROM muc_light_occupants WHERE lserver = ?">>),
235 %% RoomS argument
236
:-(
mongoose_rdbms:prepare(muc_light_config_remove_room_domain, muc_light_config,
237 ['muc_light_rooms.lserver'],
238 <<"DELETE FROM muc_light_config WHERE room_id IN "
239 "(SELECT id FROM muc_light_rooms WHERE lserver = ?)">>),
240 %% User's LServer argument
241
:-(
mongoose_rdbms:prepare(muc_light_blocking_remove_user_domain, muc_light_blocking,
242 [lserver],
243 <<"DELETE FROM muc_light_blocking WHERE lserver = ?">>),
244 %% RoomS argument
245
:-(
mongoose_rdbms:prepare(muc_light_rooms_remove_room_domain, muc_light_rooms,
246 [lserver],
247 <<"DELETE FROM muc_light_rooms WHERE lserver = ?">>),
248
:-(
ok.
249
250 %% ------------------------ Room SQL functions ------------------------
251
252 select_room_id(HostType, RoomU, RoomS) ->
253
:-(
mongoose_rdbms:execute_successfully(
254 HostType, muc_light_select_room_id, [RoomU, RoomS]).
255
256 select_room_id_and_version(HostType, RoomU, RoomS) ->
257
:-(
mongoose_rdbms:execute_successfully(
258 HostType, muc_light_select_room_id_and_version, [RoomU, RoomS]).
259
260 select_user_rooms(HostType, LUser, LServer) ->
261
:-(
mongoose_rdbms:execute_successfully(
262 HostType, muc_light_select_user_rooms, [LUser, LServer]).
263
264 select_user_rooms_count(HostType, LUser, LServer) ->
265
:-(
mongoose_rdbms:execute_successfully(
266 HostType, muc_light_select_user_rooms_count, [LUser, LServer]).
267
268 insert_room(HostType, RoomU, RoomS, Version) ->
269
:-(
mongoose_rdbms:execute_successfully(
270 HostType, muc_light_insert_room, [RoomU, RoomS, Version]).
271
272 update_room_version(HostType, RoomU, RoomS, Version) ->
273
:-(
mongoose_rdbms:execute_successfully(
274 HostType, muc_light_update_room_version, [Version, RoomU, RoomS]).
275
276 delete_room(HostType, RoomU, RoomS) ->
277
:-(
mongoose_rdbms:execute_successfully(
278 HostType, muc_light_delete_room, [RoomU, RoomS]).
279
280 %% ------------------------ Affiliation SQL functions ------------------------
281
282 %% Returns affiliations with a version
283 select_affs_by_us(HostType, RoomU, RoomS) ->
284
:-(
mongoose_rdbms:execute_successfully(
285 HostType, muc_light_select_affs_by_us, [RoomU, RoomS]).
286
287 %% Returns affiliations without a version
288 select_affs_by_room_id(HostType, RoomID) ->
289
:-(
mongoose_rdbms:execute_successfully(
290 HostType, muc_light_select_affs_by_room_id, [RoomID]).
291
292 insert_aff(HostType, RoomID, UserU, UserS, Aff) ->
293
:-(
DbAff = aff_atom2db(Aff),
294
:-(
mongoose_rdbms:execute_successfully(
295 HostType, muc_light_insert_aff, [RoomID, UserU, UserS, DbAff]).
296
297 update_aff(HostType, RoomID, UserU, UserS, Aff) ->
298
:-(
DbAff = aff_atom2db(Aff),
299
:-(
mongoose_rdbms:execute_successfully(
300 HostType, muc_light_update_aff, [DbAff, RoomID, UserU, UserS]).
301
302 delete_affs(HostType, RoomID) ->
303
:-(
mongoose_rdbms:execute_successfully(
304 HostType, muc_light_delete_affs, [RoomID]).
305
306 delete_aff(HostType, RoomID, UserU, UserS) ->
307
:-(
mongoose_rdbms:execute_successfully(
308 HostType, muc_light_delete_aff, [RoomID, UserU, UserS]).
309
310 %% ------------------------ Config SQL functions ---------------------------
311 select_config_by_room_id(HostType, RoomID) ->
312
:-(
mongoose_rdbms:execute_successfully(
313 HostType, muc_light_select_config_by_room_id, [RoomID]).
314
315 select_config_by_us(HostType, RoomU, RoomS) ->
316
:-(
mongoose_rdbms:execute_successfully(
317 HostType, muc_light_select_config_by_us, [RoomU, RoomS]).
318
319 insert_config(HostType, RoomID, Key, Val) ->
320
:-(
mongoose_rdbms:execute_successfully(
321 HostType, muc_light_insert_config, [RoomID, Key, Val]).
322
323 update_config(HostType, RoomID, Key, Val) ->
324
:-(
mongoose_rdbms:execute_successfully(
325 HostType, muc_light_update_config, [Val, RoomID, Key]).
326
327 delete_config(HostType, RoomID) ->
328
:-(
mongoose_rdbms:execute_successfully(
329 HostType, muc_light_delete_config, [RoomID]).
330
331 %% ------------------------ Blocking SQL functions -------------------------
332
333 select_blocking(HostType, LUser, LServer) ->
334
:-(
mongoose_rdbms:execute_successfully(
335 HostType, muc_light_select_blocking, [LUser, LServer]).
336
337 select_blocking_cnt(HostType, LUser, LServer, [{What, Who}]) ->
338
:-(
DbWhat = what_atom2db(What),
339
:-(
DbWho = jid:to_binary(Who),
340
:-(
mongoose_rdbms:execute_successfully(
341 HostType, muc_light_select_blocking_cnt,
342 [LUser, LServer, DbWhat, DbWho]);
343 select_blocking_cnt(HostType, LUser, LServer, [{What1, Who1}, {What2, Who2}]) ->
344
:-(
DbWhat1 = what_atom2db(What1),
345
:-(
DbWhat2 = what_atom2db(What2),
346
:-(
DbWho1 = jid:to_binary(Who1),
347
:-(
DbWho2 = jid:to_binary(Who2),
348
:-(
mongoose_rdbms:execute_successfully(
349 HostType, muc_light_select_blocking_cnt2,
350 [LUser, LServer, DbWhat1, DbWho1, DbWhat2, DbWho2]).
351
352 insert_blocking(HostType, LUser, LServer, What, Who) ->
353
:-(
DbWhat = what_atom2db(What),
354
:-(
DbWho = jid:to_binary(Who),
355
:-(
mongoose_rdbms:execute_successfully(
356 HostType, muc_light_insert_blocking,
357 [LUser, LServer, DbWhat, DbWho]).
358
359 delete_blocking1(HostType, LUser, LServer, What, Who) ->
360
:-(
DbWhat = what_atom2db(What),
361
:-(
DbWho = jid:to_binary(Who),
362
:-(
mongoose_rdbms:execute_successfully(
363 HostType, muc_light_delete_blocking1,
364 [LUser, LServer, DbWhat, DbWho]).
365
366 delete_blocking(HostType, UserU, UserS) ->
367
:-(
mongoose_rdbms:execute_successfully(
368 HostType, muc_light_delete_blocking, [UserU, UserS]).
369
370 %% ------------------------ General room management ------------------------
371
372 -spec create_room(HostType :: mongooseim:host_type(),
373 RoomUS :: jid:simple_bare_jid(), Config :: mod_muc_light_room_config:kv(),
374 AffUsers :: aff_users(), Version :: binary()) ->
375 {ok, FinalRoomUS :: jid:simple_bare_jid()} | {error, exists}.
376 create_room(HostType, {<<>>, RoomS}, Config, AffUsers, Version) ->
377
:-(
create_room_with_random_name(HostType, RoomS, Config, AffUsers, Version, 10);
378 create_room(HostType, RoomUS, Config, AffUsers, Version) ->
379
:-(
create_room_with_specified_name(HostType, RoomUS, Config, AffUsers, Version).
380
381 create_room_with_random_name(_HostType, RoomS, _Config, _AffUsers, _Version, 0) ->
382
:-(
?LOG_ERROR(#{what => muc_create_room_with_random_name_failed,
383
:-(
sub_host => RoomS}),
384
:-(
error(create_room_with_random_name_failed);
385 create_room_with_random_name(HostType, RoomS, Config, AffUsers, Version, Retries)
386 when Retries > 0 ->
387
:-(
RoomU = mongoose_bin:gen_from_timestamp(),
388
:-(
RoomUS = {RoomU, RoomS},
389
:-(
F = fun() -> create_room_transaction(HostType, RoomUS, Config, AffUsers, Version) end,
390
:-(
case mongoose_rdbms:sql_transaction(HostType, F) of
391 {atomic, ok} ->
392
:-(
{ok, RoomUS};
393 Other ->
394
:-(
?LOG_ERROR(#{what => muc_create_room_with_random_name_retry,
395
:-(
candidate_room => RoomU, sub_host => RoomS, reason => Other}),
396
:-(
create_room_with_random_name(HostType, RoomS, Config, AffUsers, Version, Retries-1)
397 end.
398
399 create_room_with_specified_name(HostType, RoomUS, Config, AffUsers, Version) ->
400
:-(
F = fun() -> create_room_transaction(HostType, RoomUS, Config, AffUsers, Version) end,
401
:-(
case mongoose_rdbms:sql_transaction(HostType, F) of
402 {atomic, ok} ->
403
:-(
{ok, RoomUS};
404 Other ->
405
:-(
case room_exists(HostType, RoomUS) of
406 true ->
407
:-(
{error, exists};
408 false -> %% Some unknown error condition
409
:-(
{RoomU, RoomS} = RoomUS,
410
:-(
?LOG_ERROR(#{what => muc_create_room_with_specified_name_failed,
411
:-(
room => RoomU, sub_host => RoomS, reason => Other}),
412
:-(
error(create_room_with_specified_name_failed)
413 end
414 end.
415
416 -spec destroy_room(HostType :: mongooseim:host_type(),
417 RoomUS :: jid:simple_bare_jid()) ->
418 ok | {error, not_exists}.
419 destroy_room(HostType, RoomUS) ->
420
:-(
F = fun() -> destroy_room_transaction(HostType, RoomUS) end,
421
:-(
{atomic, Res} = mongoose_rdbms:sql_transaction(HostType, F),
422
:-(
Res.
423
424 -spec room_exists(HostType :: mongooseim:host_type(),
425 RoomUS :: jid:simple_bare_jid()) -> boolean().
426 room_exists(HostType, {RoomU, RoomS}) ->
427
:-(
{selected, Res} = select_room_id(HostType, RoomU, RoomS),
428
:-(
Res /= [].
429
430 -spec get_user_rooms(HostType :: mongooseim:host_type(),
431 UserUS :: jid:simple_bare_jid(),
432 MUCServer :: jid:lserver() | undefined) ->
433 [RoomUS :: jid:simple_bare_jid()].
434 get_user_rooms(HostType, {LUser, LServer}, undefined) ->
435 %% Only one hosttype is handled here
436 %% It is used to be map over MYHOSTS
437
:-(
{selected, Rooms} = select_user_rooms(HostType, LUser, LServer),
438
:-(
lists:usort(Rooms);
439 get_user_rooms(HostType, {LUser, LServer}, _MUCServer) ->
440
:-(
{selected, Rooms} = select_user_rooms(HostType, LUser, LServer),
441
:-(
Rooms.
442
443 -spec get_user_rooms_count(HostType :: mongooseim:host_type(),
444 UserUS :: jid:simple_bare_jid()) ->
445 non_neg_integer().
446 get_user_rooms_count(HostType, {LUser, LServer}) ->
447
:-(
{selected, [{Cnt}]} = select_user_rooms_count(HostType, LUser, LServer),
448
:-(
mongoose_rdbms:result_to_integer(Cnt).
449
450 -spec remove_user(HostType :: mongooseim:host_type(),
451 UserUS :: jid:simple_bare_jid(),
452 Version :: binary()) ->
453 mod_muc_light_db_backend:remove_user_return() | {error, term()}.
454 remove_user(HostType, {_, UserS} = UserUS, Version) ->
455
:-(
F = fun() -> remove_user_transaction(HostType, UserUS, Version) end,
456
:-(
{atomic, Res} = mongoose_rdbms:sql_transaction(UserS, F),
457
:-(
Res.
458
459 -spec remove_domain(mongooseim:host_type(), jid:lserver(), jid:lserver()) -> ok.
460 remove_domain(HostType, RoomS, LServer) ->
461
:-(
F = fun() ->
462
:-(
mongoose_rdbms:execute_successfully(
463 HostType, muc_light_occupants_remove_room_domain, [RoomS]),
464
:-(
mongoose_rdbms:execute_successfully(
465 HostType, muc_light_occupants_remove_user_domain, [LServer]),
466
:-(
mongoose_rdbms:execute_successfully(
467 HostType, muc_light_config_remove_room_domain, [RoomS]),
468
:-(
mongoose_rdbms:execute_successfully(
469 HostType, muc_light_blocking_remove_user_domain, [LServer]),
470
:-(
mongoose_rdbms:execute_successfully(
471 HostType, muc_light_rooms_remove_room_domain, [RoomS]),
472
:-(
ok
473 end,
474
:-(
{atomic, ok} = mongoose_rdbms:sql_transaction(HostType, F),
475
:-(
ok.
476
477 %% ------------------------ Configuration manipulation ------------------------
478
479 -spec get_config(HostType :: mongooseim:host_type(),
480 RoomUS :: jid:simple_bare_jid()) ->
481 {ok, mod_muc_light_room_config:kv(), Version :: binary()} | {error, not_exists}.
482 get_config(HostType, {RoomU, RoomS}) ->
483
:-(
{selected, Result} = select_config_by_us(HostType, RoomU, RoomS),
484
:-(
case Result of
485 [] ->
486
:-(
{error, not_exists};
487 [{Version, null, null}] ->
488
:-(
{ok, [], Version};
489 [{Version, _, _} | _] ->
490
:-(
RawConfig = [{Key, Val} || {_, Key, Val} <- Result],
491
:-(
{ok, Config} = mod_muc_light_room_config:from_binary_kv(
492 RawConfig, mod_muc_light:config_schema(RoomS)),
493
:-(
{ok, Config, Version}
494 end.
495
496 -spec set_config(HostType :: mongooseim:host_type(),
497 RoomUS :: jid:simple_bare_jid(), Config :: mod_muc_light_room_config:kv(),
498 Version :: binary()) ->
499 {ok, PrevVersion :: binary()} | {error, not_exists}.
500 set_config(HostType, RoomUS, ConfigChanges, Version) ->
501
:-(
{atomic, Res}
502 = mongoose_rdbms:sql_transaction(
503
:-(
HostType, fun() -> set_config_transaction(RoomUS, ConfigChanges, Version) end),
504
:-(
Res.
505
506 %% ------------------------ Blocking manipulation ------------------------
507
508 -spec get_blocking(HostType :: mongooseim:host_type(),
509 UserUS :: jid:simple_bare_jid(), MUCServer :: jid:lserver()) ->
510 [blocking_item()].
511 get_blocking(HostType, {LUser, LServer}, _MUCServer) ->
512
:-(
{selected, WhatWhos} = select_blocking(HostType, LUser, LServer),
513
:-(
decode_blocking(WhatWhos).
514
515 -spec get_blocking(HostType :: mongooseim:host_type(),
516 UserUS :: jid:simple_bare_jid(),
517 MUCServer :: jid:lserver(),
518 WhatWhos :: [{blocking_what(), jid:simple_bare_jid()}]) ->
519 blocking_action().
520 get_blocking(HostType, {LUser, LServer}, _MUCServer, WhatWhos) ->
521
:-(
{selected, [{Count}]} = select_blocking_cnt(HostType, LUser, LServer, WhatWhos),
522
:-(
case mongoose_rdbms:result_to_integer(Count) of
523
:-(
0 -> allow;
524
:-(
_ -> deny
525 end.
526
527 -spec set_blocking(HostType :: mongooseim:host_type(),
528 UserUS :: jid:simple_bare_jid(),
529 MUCServer :: jid:lserver(),
530 BlockingItems :: [blocking_item()]) -> ok.
531 set_blocking(HostType, UserUS, MUCServer, BlockingItems) ->
532
:-(
set_blocking_loop(HostType, UserUS, MUCServer, BlockingItems).
533
534 set_blocking_loop(_HostType, _UserUS, _MUCServer, []) ->
535
:-(
ok;
536 set_blocking_loop(HostType, {LUser, LServer} = UserUS, MUCServer,
537 [{What, deny, Who} | RBlockingItems]) ->
538
:-(
{updated, _} = insert_blocking(HostType, LUser, LServer, What, Who),
539
:-(
set_blocking_loop(HostType, UserUS, MUCServer, RBlockingItems);
540 set_blocking_loop(HostType, {LUser, LServer} = UserUS, MUCServer,
541 [{What, allow, Who} | RBlockingItems]) ->
542
:-(
{updated, _} = delete_blocking1(HostType, LUser, LServer, What, Who),
543
:-(
set_blocking_loop(HostType, UserUS, MUCServer, RBlockingItems).
544
545 %% ------------------------ Affiliations manipulation ------------------------
546
547 -spec get_aff_users(HostType :: mongooseim:host_type(),
548 RoomUS :: jid:simple_bare_jid()) ->
549 {ok, aff_users(), Version :: binary()} | {error, not_exists}.
550 get_aff_users(HostType, {RoomU, RoomS}) ->
551
:-(
case select_affs_by_us(HostType, RoomU, RoomS) of
552 {selected, []} ->
553
:-(
{error, not_exists};
554 {selected, [{Version, null, null, null}]} ->
555
:-(
{ok, [], Version};
556 {selected, [{Version, _, _, _} | _] = Res} ->
557
:-(
AffUsers = decode_affs_with_versions(Res),
558
:-(
{ok, AffUsers, Version}
559 end.
560
561 -spec modify_aff_users(HostType :: mongooseim:host_type(),
562 RoomUS :: jid:simple_bare_jid(),
563 AffUsersChanges :: aff_users(),
564 ExternalCheck :: external_check_fun(),
565 Version :: binary()) ->
566 mod_muc_light_db_backend:modify_aff_users_return().
567 modify_aff_users(HostType, RoomUS, AffUsersChanges, ExternalCheck, Version) ->
568
:-(
F = fun() -> modify_aff_users_transaction(HostType, RoomUS, AffUsersChanges,
569 ExternalCheck, Version) end,
570
:-(
{atomic, Res} = mongoose_rdbms:sql_transaction(HostType, F),
571
:-(
Res.
572
573 %% ------------------------ Misc ------------------------
574
575 -spec get_info(HostType :: mongooseim:host_type(),
576 RoomUS :: jid:simple_bare_jid()) ->
577 {ok, mod_muc_light_room_config:kv(), aff_users(), Version :: binary()}
578 | {error, not_exists}.
579 get_info(HostType, {RoomU, RoomS}) ->
580
:-(
case select_room_id_and_version(HostType, RoomU, RoomS) of
581 {selected, [{DbRoomID, Version}]} ->
582
:-(
RoomID = mongoose_rdbms:result_to_integer(DbRoomID),
583
:-(
{selected, AffUsersDB} = select_affs_by_room_id(HostType, RoomID),
584
:-(
AffUsers = decode_affs(AffUsersDB),
585
:-(
{selected, ConfigDB} = select_config_by_room_id(HostType, RoomID),
586
:-(
{ok, Config} = mod_muc_light_room_config:from_binary_kv(
587 ConfigDB, mod_muc_light:config_schema(RoomS)),
588
589
:-(
{ok, Config, AffUsers, Version};
590 {selected, []} ->
591
:-(
{error, not_exists}
592 end.
593
594 %% ------------------------ Conversions ------------------------
595
596 decode_affs(AffUsersDB) ->
597
:-(
US2Aff = [{{UserU, UserS}, aff_db2atom(Aff)}
598
:-(
|| {UserU, UserS, Aff} <- AffUsersDB],
599
:-(
lists:sort(US2Aff).
600
601 decode_affs_with_versions(AffUsersDB) ->
602
:-(
US2Aff = [{{UserU, UserS}, aff_db2atom(Aff)}
603
:-(
|| {_Version, UserU, UserS, Aff} <- AffUsersDB],
604
:-(
lists:sort(US2Aff).
605
606 decode_blocking(WhatWhos) ->
607
:-(
[ {what_db2atom(What), deny, jid:to_lus(jid:from_binary(Who))}
608
:-(
|| {What, Who} <- WhatWhos ].
609
610 -spec what_db2atom(binary() | pos_integer()) -> blocking_what().
611
:-(
what_db2atom(1) -> room;
612
:-(
what_db2atom(2) -> user;
613
:-(
what_db2atom(Bin) -> what_db2atom(mongoose_rdbms:result_to_integer(Bin)).
614
615 -spec what_atom2db(blocking_what()) -> non_neg_integer().
616
:-(
what_atom2db(room) -> 1;
617
:-(
what_atom2db(user) -> 2.
618
619 -spec aff_atom2db(aff()) -> non_neg_integer().
620
:-(
aff_atom2db(owner) -> 1;
621
:-(
aff_atom2db(member) -> 2.
622
623 -spec aff_db2atom(binary() | pos_integer()) -> aff().
624
:-(
aff_db2atom(1) -> owner;
625
:-(
aff_db2atom(2) -> member;
626
:-(
aff_db2atom(Bin) -> aff_db2atom(mongoose_rdbms:result_to_integer(Bin)).
627
628 %%====================================================================
629 %% API for tests
630 %%====================================================================
631
632 force_clear_statements() ->
633
:-(
[muc_light_config_delete_all,
634 muc_light_occupants_delete_all,
635 muc_light_rooms_delete_all,
636 muc_light_blocking_delete_all].
637
638 -spec force_clear() -> ok.
639 force_clear() ->
640
:-(
[mongoose_rdbms:execute_successfully(Host, Statement, [])
641
:-(
|| Host <- ?MYHOSTS, Statement <- force_clear_statements()],
642
:-(
ok.
643
644 %%====================================================================
645 %% Internal functions
646 %%====================================================================
647
648 %% ------------------------ General room management ------------------------
649
650 %% Expects config to have unique fields!
651 -spec create_room_transaction(HostType :: mongooseim:host_type(),
652 RoomUS :: jid:simple_bare_jid(),
653 Config :: mod_muc_light_room_config:kv(),
654 AffUsers :: aff_users(),
655 Version :: binary()) -> ok.
656 create_room_transaction(HostType, {RoomU, RoomS}, Config, AffUsers, Version) ->
657
:-(
insert_room(HostType, RoomU, RoomS, Version),
658
:-(
RoomID = mongoose_rdbms:selected_to_integer(select_room_id(HostType, RoomU, RoomS)),
659
:-(
Schema = mod_muc_light:config_schema(RoomS),
660
:-(
{ok, ConfigFields} = mod_muc_light_room_config:to_binary_kv(Config, Schema),
661
:-(
[insert_aff_tuple(HostType, RoomID, AffUser) || AffUser <- AffUsers],
662
:-(
[insert_config_kv(HostType, RoomID, KV) || KV <- ConfigFields],
663
:-(
ok.
664
665 insert_aff_tuple(HostType, RoomID, {{UserU, UserS}, Aff}) ->
666
:-(
insert_aff(HostType, RoomID, UserU, UserS, Aff).
667
668 insert_config_kv(HostType, RoomID, {Key, Val}) ->
669
:-(
insert_config(HostType, RoomID, Key, Val).
670
671 -spec destroy_room_transaction(HostType :: mongooseim:host_type(),
672 RoomUS :: jid:simple_bare_jid()) ->
673 ok | {error, not_exists}.
674 destroy_room_transaction(HostType, {RoomU, RoomS}) ->
675
:-(
case select_room_id(HostType, RoomU, RoomS) of
676 {selected, [{DbRoomID}]} ->
677
:-(
RoomID = mongoose_rdbms:result_to_integer(DbRoomID),
678
:-(
{updated, _} = delete_affs(HostType, RoomID),
679
:-(
{updated, _} = delete_config(HostType, RoomID),
680
:-(
{updated, _} = delete_room(HostType, RoomU, RoomS),
681
:-(
ok;
682 {selected, []} ->
683
:-(
{error, not_exists}
684 end.
685
686 -spec remove_user_transaction(HostType :: mongooseim:host_type(),
687 UserUS :: jid:simple_bare_jid(),
688 Version :: binary()) ->
689 mod_muc_light_db_backend:remove_user_return().
690 remove_user_transaction(HostType, {UserU, UserS} = UserUS, Version) ->
691
:-(
Rooms = get_user_rooms(HostType, UserUS, undefined),
692
:-(
{updated, _} = delete_blocking(HostType, UserU, UserS),
693
:-(
lists:map(
694 fun(RoomUS) ->
695
:-(
{RoomUS, modify_aff_users_transaction(HostType,
696
:-(
RoomUS, [{UserUS, none}], fun(_, _) -> ok end, Version)}
697 end, Rooms).
698
699 %% ------------------------ Configuration manipulation ------------------------
700
701 -spec set_config_transaction(RoomUS :: jid:simple_bare_jid(),
702 ConfigChanges :: mod_muc_light_room_config:kv(),
703 Version :: binary()) ->
704 {ok, PrevVersion :: binary()} | {error, not_exists}.
705 set_config_transaction({RoomU, RoomS} = RoomUS, ConfigChanges, Version) ->
706
:-(
HostType = room_us_to_host_type(RoomUS),
707
:-(
case select_room_id_and_version(HostType, RoomU, RoomS) of
708 {selected, [{DbRoomID, PrevVersion}]} ->
709
:-(
RoomID = mongoose_rdbms:result_to_integer(DbRoomID),
710
:-(
{updated, _} = update_room_version(HostType, RoomU, RoomS, Version),
711
:-(
{ok, Config} = mod_muc_light_room_config:to_binary_kv_diff(
712 ConfigChanges, mod_muc_light:config_schema(RoomS)),
713
:-(
lists:foreach(
714 fun({Key, Val}) ->
715
:-(
{updated, _} = update_config(HostType, RoomID, Key, Val)
716 end, Config),
717
:-(
{ok, PrevVersion};
718 {selected, []} ->
719
:-(
{error, not_exists}
720 end.
721
722 %% ------------------------ Blocking manipulation ------------------------
723
724 %% ------------------------ Affiliations manipulation ------------------------
725
726 -spec modify_aff_users_transaction(HostType :: mongooseim:host_type(),
727 RoomUS :: jid:simple_bare_jid(),
728 AffUsersChanges :: aff_users(),
729 CheckFun :: external_check_fun(),
730 Version :: binary()) ->
731 mod_muc_light_db_backend:modify_aff_users_return().
732 modify_aff_users_transaction(HostType, {RoomU, RoomS} = RoomUS,
733 AffUsersChanges, CheckFun, Version) ->
734
:-(
case select_room_id_and_version(HostType, RoomU, RoomS) of
735 {selected, [{DbRoomID, PrevVersion}]} ->
736
:-(
RoomID = mongoose_rdbms:result_to_integer(DbRoomID),
737
:-(
modify_aff_users_transaction(HostType,
738 RoomUS, RoomID, AffUsersChanges, CheckFun, PrevVersion, Version);
739 {selected, []} ->
740
:-(
{error, not_exists}
741 end.
742
743 -spec modify_aff_users_transaction(HostType :: mongooseim:host_type(),
744 RoomUS :: jid:simple_bare_jid(),
745 RoomID :: room_id(),
746 AffUsersChanges :: aff_users(),
747 CheckFun :: external_check_fun(),
748 PrevVersion :: binary(),
749 Version :: binary()) ->
750 mod_muc_light_db_backend:modify_aff_users_return().
751 modify_aff_users_transaction(HostType, RoomUS, RoomID, AffUsersChanges,
752 CheckFun, PrevVersion, Version) ->
753
:-(
{selected, AffUsersDB} = select_affs_by_room_id(HostType, RoomID),
754
:-(
AffUsers = decode_affs(AffUsersDB),
755
:-(
case mod_muc_light_utils:change_aff_users(AffUsers, AffUsersChanges) of
756 {ok, NewAffUsers, AffUsersChanged, JoiningUsers, _LeavingUsers} ->
757
:-(
case CheckFun(RoomUS, NewAffUsers) of
758 ok ->
759
:-(
apply_aff_users_transaction(HostType, RoomID, AffUsersChanged, JoiningUsers),
760
:-(
{RoomU, RoomS} = RoomUS,
761
:-(
{updated, _} = update_room_version(HostType, RoomU, RoomS, Version),
762
:-(
{ok, AffUsers, NewAffUsers, AffUsersChanged, PrevVersion};
763 Error ->
764
:-(
Error
765 end;
766 Error ->
767
:-(
Error
768 end.
769
770 -spec apply_aff_users_transaction(HostType :: mongooseim:host_type(),
771 RoomID :: room_id(),
772 AffUsersChanges :: aff_users(),
773 JoiningUsers :: [jid:simple_bare_jid()]) -> ok.
774 apply_aff_users_transaction(HostType, RoomID, AffUsersChanged, JoiningUsers) ->
775
:-(
lists:foreach(
776 fun({{UserU, UserS}, none}) ->
777
:-(
{updated, _} = delete_aff(HostType, RoomID, UserU, UserS);
778 ({{UserU, UserS} = UserUS, Aff}) ->
779
:-(
case lists:member(UserUS, JoiningUsers) of
780 true ->
781
:-(
{updated, _} = insert_aff(HostType, RoomID, UserU, UserS, Aff);
782 false ->
783
:-(
{updated, _} = update_aff(HostType, RoomID, UserU, UserS, Aff)
784 end
785 end, AffUsersChanged).
786
787 %% ------------------------ Common ------------------------
788
789 -spec room_us_to_host_type(jid:simple_bare_jid()) -> mongooseim:host_type().
790 room_us_to_host_type({_, RoomS}) ->
791
:-(
muc_server_to_host_type(RoomS).
792
793 -spec muc_server_to_host_type(jid:lserver()) -> mongooseim:host_type().
794 muc_server_to_host_type(MUCServer) ->
795
:-(
mod_muc_light_utils:muc_host_to_host_type(MUCServer).
Line Hits Source