Skip to content

Commit

Permalink
Merge pull request #3305 from esl/domain-removal-mod-muc
Browse files Browse the repository at this point in the history
Implement domain removal in mod_muc
  • Loading branch information
vkatsuba authored Sep 29, 2021
2 parents 0528e05 + 006655c commit ea992f5
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 35 deletions.
47 changes: 47 additions & 0 deletions big_tests/tests/domain_removal_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
-include_lib("eunit/include/eunit.hrl").
-include_lib("exml/include/exml_stream.hrl").
-include_lib("jid/include/jid.hrl").
-include_lib("common_test/include/ct.hrl").

all() ->
[{group, auth_removal},
{group, cache_removal},
{group, mam_removal},
{group, inbox_removal},
{group, muc_light_removal},
{group, muc_removal},
{group, private_removal},
{group, roster_removal},
{group, offline_removal},
Expand All @@ -30,6 +32,7 @@ groups() ->
{inbox_removal, [], [inbox_removal]},
{muc_light_removal, [], [muc_light_removal,
muc_light_blocking_removal]},
{muc_removal, [], [muc_removal]},
{private_removal, [], [private_removal]},
{roster_removal, [], [roster_removal]},
{offline_removal, [], [offline_removal]},
Expand Down Expand Up @@ -82,6 +85,9 @@ group_to_modules(mam_removal) ->
group_to_modules(muc_light_removal) ->
MucHost = subhost_pattern(muc_light_helper:muc_host_pattern()),
[{mod_muc_light, [{backend, rdbms}, {host, MucHost}]}];
group_to_modules(muc_removal) ->
MucHost = subhost_pattern(muc_helper:muc_host_pattern()),
[{mod_muc, [{backend, rdbms}, {host, MucHost}]}];
group_to_modules(inbox_removal) ->
[{mod_inbox, []}];
group_to_modules(private_removal) ->
Expand All @@ -97,12 +103,20 @@ group_to_modules(vcard_removal) ->
%%% Testcase specific setup/teardown
%%%===================================================================

init_per_testcase(muc_removal, Config) ->
muc_helper:load_muc(),
mongoose_helper:ensure_muc_clean(),
escalus:init_per_testcase(muc_removal, Config);
init_per_testcase(roster_removal, ConfigIn) ->
Config = roster_helper:set_versioning(true, true, ConfigIn),
escalus:init_per_testcase(roster_removal, Config);
init_per_testcase(TestCase, Config) ->
escalus:init_per_testcase(TestCase, Config).

end_per_testcase(muc_removal, Config) ->
mongoose_helper:ensure_muc_clean(),
muc_helper:unload_muc(),
escalus:end_per_testcase(muc_removal, Config);
end_per_testcase(roster_removal, Config) ->
roster_helper:restore_versioning(Config),
escalus:end_per_testcase(roster_removal, Config);
Expand Down Expand Up @@ -180,6 +194,27 @@ inbox_removal(Config) ->
inbox_helper:get_inbox(Bob, #{count => 0, unread_messages => 0, active_conversations => 0})
end).

muc_removal(Config0) ->
muc_helper:story_with_room(Config0, [{persistent, true}], [{alice, 1}], fun(Config, Alice) ->
AliceJid= jid:from_binary(escalus_client:full_jid(Alice)),
{_, Domain} = jid:to_lus(AliceJid),
MucHost = muc_helper:muc_host(),
% Alice joins room and registers nick
EnterRoom = muc_helper:stanza_muc_enter_room(?config(room, Config), <<"alice">>),
escalus:send(Alice, EnterRoom),
escalus:wait_for_stanzas(Alice, 2),
muc_helper:set_nick(Alice, <<"alice2">>),
% check muc tables
?assertMatch([_], get_muc_rooms(MucHost)),
?assertMatch([_], get_muc_room_aff(Domain)),
?assertMatch({ok, _}, get_muc_registered(MucHost, AliceJid)),
% remove domain and check muc tables
run_remove_domain(),
?assertMatch([], get_muc_rooms(MucHost)),
?assertMatch([], get_muc_room_aff(Domain)),
?assertMatch({error, not_registered}, get_muc_registered(MucHost, AliceJid))
end).

muc_light_removal(Config0) ->
F = fun(Config, Alice) ->
%% GIVEN a room
Expand Down Expand Up @@ -341,6 +376,18 @@ get_vcard_search_query_count(Element) ->
{element, <<"count">>},
cdata]).

get_muc_registered(MucHost, UserJid) ->
rpc(mim(), mod_muc_db_rdbms, get_nick, [host_type(), MucHost, UserJid]).

get_muc_rooms(MucHost) ->
{ok, Rooms} = rpc(mim(), mod_muc_db_rdbms, get_rooms, [host_type(), MucHost]),
Rooms.

get_muc_room_aff(Domain) ->
Query = "SELECT * FROM muc_room_aff WHERE lserver = '" ++ binary_to_list(Domain) ++ "'",
{selected, Affs} = rpc(mim(), mongoose_rdbms, sql_query, [host_type(), Query]),
Affs.

select_from_roster(Table) ->
Query = "SELECT * FROM " ++ Table ++ " WHERE server='" ++ binary_to_list(domain()) ++ "'",
{selected, Res} = rpc(mim(), mongoose_rdbms, sql_query, [host_type(), Query]),
Expand Down
37 changes: 5 additions & 32 deletions big_tests/tests/muc_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@
room_address/2,
room_address/1,
disco_service_story/1,
story_with_room/4
story_with_room/4,
stanza_form/2,
form_field/1,
change_nick_form_iq/1,
set_nick/2
]).

-import(domain_helper, [host_type/0, domain/0]).
Expand Down Expand Up @@ -4870,27 +4874,6 @@ stanza_cancel(Room) ->
stanza_to_room(escalus_stanza:iq_set(
?NS_MUC_OWNER, Payload), Room).

stanza_form(Payload, Type) ->
#xmlel{
name = <<"x">>,
attrs = [{<<"xmlns">>,<<"jabber:x:data">>}, {<<"type">>,<<"submit">>}],
children = [form_field({<<"FORM_TYPE">>, Type, <<"hidden">>}) | Payload]
}.

form_field_item(Value) ->
#xmlel{ name = <<"value">>,
children = [#xmlcdata{content = Value}]}.

form_field({Var, Value, Type}) when is_list(Value) ->
#xmlel{ name = <<"field">>,
attrs = [{<<"var">>, Var},{<<"type">>, Type}],
children = [form_field_item(V) || V <- Value]};
form_field({Var, Value, Type}) ->
#xmlel{ name = <<"field">>,
attrs = [{<<"type">>, Type},{<<"var">>, Var}],
children = [#xmlel{name = <<"value">>,
children = [#xmlcdata{content = Value}] }] }.

stanza_instant_room(Room) ->
X = #xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_DATA_FORMS},
{<<"type">>, <<"submit">>}]},
Expand Down Expand Up @@ -4931,22 +4914,12 @@ get_nick_form_iq() ->
GetIQ = escalus_stanza:iq_get(<<"jabber:iq:register">>, []),
escalus_stanza:to(GetIQ, muc_host()).

change_nick_form_iq(Nick) ->
NS = <<"jabber:iq:register">>,
NickField = form_field({<<"nick">>, Nick, <<"text-single">>}),
Form = stanza_form([NickField], NS),
SetIQ = escalus_stanza:iq_set(NS, [Form]),
escalus_stanza:to(SetIQ, muc_host()).

remove_nick_form_iq() ->
NS = <<"jabber:iq:register">>,
RemoveEl = #xmlel{name = <<"remove">>},
SetIQ = escalus_stanza:iq_set(NS, [RemoveEl]),
escalus_stanza:to(SetIQ, muc_host()).

set_nick(User, Nick) ->
escalus:send_iq_and_wait_for_result(User, change_nick_form_iq(Nick)).

unset_nick(User) ->
escalus:send_iq_and_wait_for_result(User, remove_nick_form_iq()).

Expand Down
35 changes: 35 additions & 0 deletions big_tests/tests/muc_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,38 @@ story_with_room(Config, RoomOpts, [{Owner, _}|_] = UserSpecs, StoryFun) ->
after
destroy_room(Config2)
end.

%%--------------------------------------------------------------------
%% Helpers (stanzas)
%%--------------------------------------------------------------------

stanza_form(Payload, Type) ->
#xmlel{
name = <<"x">>,
attrs = [{<<"xmlns">>,<<"jabber:x:data">>}, {<<"type">>,<<"submit">>}],
children = [form_field({<<"FORM_TYPE">>, Type, <<"hidden">>}) | Payload]
}.

form_field_item(Value) ->
#xmlel{ name = <<"value">>,
children = [#xmlcdata{content = Value}]}.

form_field({Var, Value, Type}) when is_list(Value) ->
#xmlel{ name = <<"field">>,
attrs = [{<<"var">>, Var},{<<"type">>, Type}],
children = [form_field_item(V) || V <- Value]};
form_field({Var, Value, Type}) ->
#xmlel{ name = <<"field">>,
attrs = [{<<"type">>, Type},{<<"var">>, Var}],
children = [#xmlel{name = <<"value">>,
children = [#xmlcdata{content = Value}] }] }.

change_nick_form_iq(Nick) ->
NS = <<"jabber:iq:register">>,
NickField = form_field({<<"nick">>, Nick, <<"text-single">>}),
Form = stanza_form([NickField], NS),
SetIQ = escalus_stanza:iq_set(NS, [Form]),
escalus_stanza:to(SetIQ, muc_helper:muc_host()).

set_nick(User, Nick) ->
escalus:send_iq_and_wait_for_result(User, change_nick_form_iq(Nick)).
18 changes: 17 additions & 1 deletion src/mod_muc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
%% Hooks handlers
-export([is_muc_room_owner/4,
can_access_room/4,
remove_domain/3,
get_room_affiliations/2,
can_access_identity/4,
disco_local_items/1]).
Expand All @@ -83,8 +84,9 @@
{?MOD_MUC_DB_BACKEND, set_nick, 4},
{?MOD_MUC_DB_BACKEND, store_room, 4},
{?MOD_MUC_DB_BACKEND, unset_nick, 3},
{?MOD_MUC_DB_BACKEND, remove_domain, 3},
can_access_identity/4, can_access_room/4, get_room_affiliations/2, create_instant_room/6,
disco_local_items/1, hibernated_rooms_number/0, is_muc_room_owner/4,
disco_local_items/1, hibernated_rooms_number/0, is_muc_room_owner/4, remove_domain/3,
online_rooms_number/0, register_room/4, restore_room/3, start_link/2
]).

Expand Down Expand Up @@ -1252,6 +1254,19 @@ can_access_room(_, _HostType, Room, User) ->
{ok, CanAccess} -> CanAccess
end.

-spec remove_domain(mongoose_hooks:simple_acc(),
mongooseim:host_type(), jid:lserver()) ->
mongoose_hooks:simple_acc().
remove_domain(Acc, HostType, Domain) ->
case backend_module:is_exported(mod_muc_db_backend, remove_domain, 3) of
true ->
MUCHost = server_host_to_muc_host(HostType, Domain),
mod_muc_db_backend:remove_domain(HostType, MUCHost, Domain);
false ->
ok
end,
Acc.

-spec get_room_affiliations(mongoose_acc:t(), jid:jid()) ->
{mongoose_acc:t(), any()}.
get_room_affiliations(Acc1, Room) ->
Expand Down Expand Up @@ -1340,6 +1355,7 @@ config_metrics(HostType) ->
hooks(HostType) ->
[{is_muc_room_owner, HostType, ?MODULE, is_muc_room_owner, 50},
{can_access_room, HostType, ?MODULE, can_access_room, 50},
{remove_domain, HostType, ?MODULE, remove_domain, 50},
{get_room_affiliations, HostType, ?MODULE, get_room_affiliations, 50},
{can_access_identity, HostType, ?MODULE, can_access_identity, 50},
{disco_local_items, HostType, ?MODULE, disco_local_items, 250}].
Expand Down
4 changes: 4 additions & 0 deletions src/mod_muc_db.erl
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@
%% Unregistered nicks can be used by someone else
-callback unset_nick(server_host(), muc_host(), client_jid()) ->
ok | {error, term()}.

-callback remove_domain(mongooseim:host_type(), muc_host(), jid:lserver()) -> ok.

-optional_callbacks([remove_domain/3]).
39 changes: 37 additions & 2 deletions src/mod_muc_db_rdbms.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
can_use_nick/4,
get_nick/3,
set_nick/4,
unset_nick/3
unset_nick/3,
remove_domain/3
]).

-ignore_xref([can_use_nick/4, forget_room/3, get_nick/3, get_rooms/2, init/2,
-ignore_xref([can_use_nick/4, forget_room/3, get_nick/3, get_rooms/2, remove_domain/3, init/2,
restore_room/3, set_nick/4, store_room/4, unset_nick/3]).

-import(mongoose_rdbms, [prepare/4, execute_successfully/3]).
Expand Down Expand Up @@ -56,6 +57,9 @@ prepare_queries(ServerHost) ->
prepare(muc_delete_room, muc_rooms,
[muc_host, room_name],
<<"DELETE FROM muc_rooms WHERE muc_host = ? AND room_name = ?">>),
prepare(muc_rooms_remove_domain, muc_rooms,
[muc_host],
<<"DELETE FROM muc_rooms WHERE muc_host = ?">>),
prepare(muc_select_rooms, muc_rooms, [muc_host],
<<"SELECT id, room_name, options FROM muc_rooms WHERE muc_host = ?">>),
%% Queries to muc_room_aff table
Expand All @@ -70,6 +74,13 @@ prepare_queries(ServerHost) ->
"FROM muc_room_aff WHERE room_id = ?">>),
prepare(muc_delete_aff, muc_room_aff, [room_id],
<<"DELETE FROM muc_room_aff WHERE room_id = ?">>),
prepare(muc_room_aff_remove_room_domain, muc_room_aff,
['muc_rooms.muc_host'],
<<"DELETE FROM muc_room_aff WHERE room_id IN "
"(SELECT id FROM muc_rooms WHERE muc_host = ?)">>),
prepare(muc_room_aff_remove_user_domain, muc_room_aff,
[lserver],
<<"DELETE FROM muc_room_aff WHERE lserver = ?">>),
%% Queries to muc_registered table
prepare(muc_select_nick_user, muc_registered,
[muc_host, lserver, nick],
Expand All @@ -83,6 +94,12 @@ prepare_queries(ServerHost) ->
[muc_host, lserver, luser],
<<"DELETE FROM muc_registered WHERE muc_host = ?"
" AND lserver = ? AND luser = ?">>),
prepare(muc_registered_remove_room_domain, muc_registered,
[muc_host],
<<"DELETE FROM muc_registered WHERE muc_host = ?">>),
prepare(muc_registered_remove_user_domain, muc_registered,
[lserver],
<<"DELETE FROM muc_room_aff WHERE lserver = ?">>),
rdbms_queries:prepare_upsert(ServerHost, muc_nick_upsert, muc_registered,
[<<"muc_host">>, <<"luser">>, <<"lserver">>, <<"nick">>],
[<<"nick">>],
Expand All @@ -91,6 +108,24 @@ prepare_queries(ServerHost) ->

%% Room API functions

-spec remove_domain(mongooseim:host_type(), muc_host(), jid:lserver()) -> ok.
remove_domain(HostType, MucHost, Domain) ->
F = fun() ->
mongoose_rdbms:execute_successfully(
HostType, muc_registered_remove_room_domain, [MucHost]),
mongoose_rdbms:execute_successfully(
HostType, muc_registered_remove_user_domain, [Domain]),
mongoose_rdbms:execute_successfully(
HostType, muc_room_aff_remove_room_domain, [MucHost]),
mongoose_rdbms:execute_successfully(
HostType, muc_room_aff_remove_user_domain, [Domain]),
mongoose_rdbms:execute_successfully(
HostType, muc_rooms_remove_domain, [MucHost]),
ok
end,
{atomic, ok} = mongoose_rdbms:sql_transaction(HostType, F),
ok.

-spec store_room(server_host(), muc_host(), mod_muc:room(), room_opts()) ->
ok | {error, term()}.
store_room(ServerHost, MucHost, RoomName, Opts) ->
Expand Down

0 comments on commit ea992f5

Please sign in to comment.