From 56001600a843830cea91b44453bd1b76a8e77dad Mon Sep 17 00:00:00 2001 From: Pawel Kowalczuk Date: Mon, 15 Oct 2018 16:54:01 +0200 Subject: [PATCH] room storing is now transactional --- src/mod_muc.erl | 10 ++++++++++ src/mod_muc_admin.erl | 29 ++++++++++++++++++++++++++++- src/mod_muc_sql.erl | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 2c10435b61b..f7812e2373c 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -38,6 +38,7 @@ stop/1, reload/3, room_destroyed/4, + store_rooms/4, store_room/4, store_room/5, restore_room/3, @@ -91,6 +92,7 @@ -callback init(binary(), gen_mod:opts()) -> any(). -callback import(binary(), binary(), [binary()]) -> ok. -callback store_room(binary(), binary(), binary(), list(), list()|undefined) -> {atomic, any()}. +-callback store_rooms(binary(), binary(), binary(), list(), list()|undefined) -> {atomic, any()}. -callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error. -callback forget_room(binary(), binary(), binary()) -> {atomic, any()}. -callback can_use_nick(binary(), binary(), jid(), binary()) -> boolean(). @@ -159,6 +161,14 @@ create_room(Host, Name, From, Nick, Opts) -> Proc = gen_mod:get_module_proc(ServerHost, ?MODULE), gen_server:call(Proc, {create, Name, Host, From, Nick, Opts}). +store_rooms(ServerHost, Host, Names, Opts) -> + store_rooms(ServerHost, Host, Names, Opts, undefined). + +store_rooms(ServerHost, Host, Names, Opts, ChangesHints) -> + LServer = jid:nameprep(ServerHost), + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:store_rooms(LServer, Host, Names, Opts, ChangesHints). + store_room(ServerHost, Host, Name, Opts) -> store_room(ServerHost, Host, Name, Opts, undefined). diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index bf943f6777b..d35536d5459 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -37,7 +37,7 @@ get_user_rooms/2, get_room_occupants/2, get_room_occupants_number/2, send_direct_invitation/5, change_room_option/4, get_room_options/2, - set_room_affiliation/4, get_room_affiliations/2, get_room_affiliation/3, + set_room_affiliation/4, set_rooms_affiliations/4, get_room_affiliations/2, get_room_affiliation/3, web_menu_main/2, web_page_main/2, web_menu_host/3, subscribe_room/4, unsubscribe_room/2, get_subscribers/2, web_page_host/3, mod_options/1, get_commands_spec/0]). @@ -298,6 +298,14 @@ get_commands_spec() -> args = [{name, binary}, {service, binary}, {jid, binary}, {affiliation, binary}], result = {res, rescode}}, + #ejabberd_commands{name = set_rooms_affiliations, tags = [muc_room], + desc = "Change and affiliation for multiple rooms in one transaction", + module = ?MODULE, function = set_rooms_affiliations, + args_desc = ["Room names", "MUC service", "Users JIDs", "member"], + args_example = ["[room1, room2]", "muc.example.com", "[user2@wxample.com]", "member"], + args = [{name, binary}, {service, binary}, + {jid, binary}, {affiliation, binary}], + result = {res, rescode}}, #ejabberd_commands{name = get_room_affiliations, tags = [muc_room], desc = "Get the list of affiliations of a MUC room", module = ?MODULE, function = get_room_affiliations, @@ -1085,6 +1093,25 @@ set_room_affiliation(Name, Service, JID, AffiliationString) -> error end. +set_rooms_affiliations(Names, Service, JIDS, AffiliationString) -> + Affiliation = misc:binary_to_atom(AffiliationString), + States = + lists:map(fun(Name) -> + case mod_muc:find_online_room(Name, Service) of + {ok, Pid} -> + StateDatas = lists:map(fun(JID) -> + {ok, StateData} = p1_fsm:sync_send_all_state_event(Pid, {process_item_change, {jid:decode(JID), affiliation, Affiliation, <<"">>}, undefined}), + StateData + end, JIDS), + lists:last(StateDatas); + error -> + error + end + end, Names), + [First| _] = States, + Opts = lists:map(fun(S) -> make_opts(S) end, States), + mod_muc:store_rooms(First#state.server_host, First#state.host, Names, Opts). + %%% %%% MUC Subscription %%% diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index 8166e86738a..c4e08c15fac 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -30,7 +30,7 @@ -behaviour(mod_muc_room). %% API --export([init/2, store_room/5, restore_room/3, forget_room/3, +-export([init/2, store_room/5, store_rooms/5, restore_room/3, forget_room/3, can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4, import/3, export/1]). -export([register_online_room/4, unregister_online_room/4, find_online_room/3, @@ -57,6 +57,34 @@ init(Host, Opts) -> ok end. +store_rooms(LServer, Host, Names, Opts, ChangesHints) -> + Transactions = lists:map(fun({Name, Opt}) -> + {Subs, Opts2} = case lists:keytake(subscribers, 1, Opt) of + {value, {subscribers, S}, OptN} -> {S, OptN}; + _ -> {[], Opt} + end, + SOpts = misc:term_to_expr(Opts2), + F = fun () -> + ?SQL_UPSERT_T( + "muc_room", + ["!name=%(Name)s", + "!host=%(Host)s", + "server_host=%(LServer)s", + "opts=%(SOpts)s"]), + case ChangesHints of + Changes when is_list(Changes) -> + [change_room(Host, Name, Change) || Change <- Changes]; + _ -> + ejabberd_sql:sql_query_t( + ?SQL("delete from muc_room_subscribers where " + "room=%(Name)s and host=%(Host)s")), + [change_room(Host, Name, {add_subscription, JID, Nick, Nodes}) + || {JID, Nick, Nodes} <- Subs] + end + end + end, lists:zip(Names, Opts)), + ejabberd_sql:sql_transaction(LServer, Transactions). + store_room(LServer, Host, Name, Opts, ChangesHints) -> {Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of {value, {subscribers, S}, OptN} -> {S, OptN}; @@ -64,6 +92,7 @@ store_room(LServer, Host, Name, Opts, ChangesHints) -> end, SOpts = misc:term_to_expr(Opts2), F = fun () -> + ?SQL_UPSERT_T( "muc_room", ["!name=%(Name)s", @@ -83,6 +112,8 @@ store_room(LServer, Host, Name, Opts, ChangesHints) -> end, ejabberd_sql:sql_transaction(LServer, F). + + change_room(Host, Room, {add_subscription, JID, Nick, Nodes}) -> SJID = jid:encode(JID), SNodes = misc:term_to_expr(Nodes),