diff --git a/rel/files/mongooseim.cfg b/rel/files/mongooseim.cfg index ebeb90dd926..215207e3642 100755 --- a/rel/files/mongooseim.cfg +++ b/rel/files/mongooseim.cfg @@ -640,7 +640,7 @@ {services, [ {service_admin_extra, [{submods, [node, accounts, sessions, vcard, gdpr, upload, - roster, last, private, stanza, stats]}]}, + roster, last, private, stanza, stats, migration]}]}, {service_mongoose_system_metrics, [{initial_report, 300000}, {periodic_report, 10800000}]} ] diff --git a/src/admin_extra/service_admin_extra_migration.erl b/src/admin_extra/service_admin_extra_migration.erl new file mode 100644 index 00000000000..41372a970f3 --- /dev/null +++ b/src/admin_extra/service_admin_extra_migration.erl @@ -0,0 +1,724 @@ +%%% ================================================================== +%%% @doc +%%% MongooseIM migration +%%% @end +%%% ================================================================== + +-module(service_admin_extra_migration). + +-export([commands/0, migrate/3, get_data/2]). + +-export([ + migrate_pubsub_nodes/1, + migrate_pubsub_affiliations/1, + migrate_pubsub_subscriptions/1, + migrate_pubsub_items/1, + migrate_vcard/1, + migrate_vcard_search/1, + migrate_users/1, + migrate_event_pusher_push_subscription/1, + migrate_rosterusers/1, + migrate_roster_version/1, + migrate_rostergroups/1, + migrate_last/1, + migrate_private_storage/1, + migrate_offline_message/1, + migrate_muc_light_rooms/1 +]). + +%%% ================================================================== +%%% Includes +%%% ================================================================== + +-include("jlib.hrl"). +-include("pubsub.hrl"). +-include("mongoose.hrl"). +-include("mod_last.hrl"). +-include("mod_vcard.hrl"). +-include("mod_roster.hrl"). +-include("mod_offline.hrl"). +-include("ejabberd_commands.hrl"). + +%%% ================================================================== +%%% API +%%% ================================================================== + +%% ------------------------------------------------------------------- +%% @doc +%% Commands of migration CTL +%% @end +%% ------------------------------------------------------------------- +-spec commands() -> [ejabberd_commands:cmd()]. + +commands() -> + [#ejabberd_commands{ + name = migrate, + tags = [migration], + desc = "Migration from Mnesia to MySQL", + module = ?MODULE, + function = migrate, + args = [{from, binary}, {to, binary}, {act, binary}], + result = {res, restuple} + }]. + +%% ------------------------------------------------------------------- +%% @doc +%% Migrate from DB to DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate(From :: binary(), To :: binary(), Act :: binary()) -> Result :: tuple(). + +migrate(<<"mnesia">>, <<"rdbms">>, Act) when is_binary(Act) -> + OP = ejabberd_config:get_local_option_or_default(outgoing_pools, []), + case [X || {X, _, _, _, _} <- OP, X =:= rdbms] of + [rdbms] -> + case try_migrate(Act) of + {ok, Resp} -> + {ok, Resp}; + {error, Reason} -> + {exists, Reason} + end; + [rdbms|_] -> + {exists, "Detected multi 'rdbms' configuration. Need to use one 'rdbms' configuration for correct migration"}; + _ -> + {exists, "Looks like that the MySQL is not configured. Check 'mongooseim.cfg'"} + end; + +migrate(From, To, _) -> + {exists, io_lib:format("Migration from '~s' to '~s' is not supported", [From, To])}. + +%% ------------------------------------------------------------------- +%% @doc +%% @private +%% Trying do migrate from DB to DB +%% @end +%% ------------------------------------------------------------------- +-spec try_migrate(Act :: binary() | tuple()) -> Result :: tuple(). + +try_migrate(Act) when is_binary(Act) -> + case Act of + <<"all">> -> + Acts = [<<"pubsub_nodes">>, <<"pubsub_affiliations">>, <<"pubsub_subscriptions">>, <<"pubsub_items">>, + <<"vcard">>, <<"vcard_search">>, <<"users">>, <<"event_pusher_push_subscription">>, + <<"rosterusers">>, <<"roster_version">>, <<"rostergroups">>, <<"last">>, <<"private_storage">>, + <<"offline_message">>, <<"muc_light_rooms">>], + _ = [try_migrate(X) || X <- Acts], + {ok, io_lib:format("Completed the migration of the tables: ~p", [Acts])}; + <<"pubsub_nodes">> -> + try_migrate({Act, pubsub_node}); + Act when Act =:= <<"pubsub_affiliations">>; Act =:= <<"pubsub_subscriptions">> -> + try_migrate({Act, pubsub_state}); + <<"pubsub_items">> -> + try_migrate({Act, pubsub_item}); + <<"vcard">> -> + try_migrate({Act, vcard}); + <<"vcard_search">> -> + try_migrate({Act, vcard_search}); + <<"users">> -> + try_migrate({Act, passwd}); + <<"event_pusher_push_subscription">> -> + try_migrate({Act, push_subscription}); + Act when Act =:= <<"rosterusers">>; Act =:= <<"rostergroups">> -> + try_migrate({Act, roster}); + <<"roster_version">> -> + try_migrate({Act, roster_version}); + <<"last">> -> + try_migrate({Act, last_activity}); + <<"private_storage">> -> + try_migrate({Act, private_storage}); + <<"offline_message">> -> + try_migrate({Act, offline_msg}); + <<"muc_light_rooms">> -> + try_migrate({Act, muc_light_room}); + Act -> + {error, io_lib:format("Migrate dont support act: ~p", [binary_to_list(Act)])} + end; + +try_migrate({Act, Table}) when is_atom(Table) -> + try_migrate({Act, Table, get_data(first, Table)}); + +try_migrate({Act, Table, TableData}) -> + case TableData of + {ok, _, '$end_of_table'} -> + {ok, io_lib:format("Completed the migration of the table: '~s'", [Act])}; + {ok, Data, NextKey} -> + ?MODULE:(list_to_existing_atom("migrate_" ++ binary_to_list(Act)))(Data), + try_migrate({Act, Table, get_data(next, {Table, NextKey})}); + Error -> + Error + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "pubsub_node" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_pubsub_nodes(Data :: list()) -> Result :: ok. + +migrate_pubsub_nodes([]) -> + ok; + +migrate_pubsub_nodes([H|_]) -> + {Host, ID} = H#pubsub_node.nodeid, + Owners = jiffy:encode([jid:to_binary(O) || O <- H#pubsub_node.owners]), + Ops = jiffy:encode({H#pubsub_node.options}), + Cols = ["nidx", "p_key", "name", "type", "owners", "options"], + Vals = [H#pubsub_node.id, Host, ID, H#pubsub_node.type, Owners, Ops], + Q = ["INSERT INTO pubsub_nodes ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'pubsub_node' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "pubsub_affiliations" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_pubsub_affiliations(Data :: list()) -> Result :: ok. + +migrate_pubsub_affiliations([]) -> + ok; + +migrate_pubsub_affiliations([H|_]) -> + {SJID, Nidx} = H#pubsub_state.stateid, + JidBIn = jid:to_binary(SJID), + JID = jid:from_binary(JidBIn), + case {JID#jid.luser, H#pubsub_state.affiliation} of + {Luser, Aff} when Aff =:= none; Luser =:= <<>> -> + ok; + _ -> + JidBIn = jid:to_binary(SJID), + JID = jid:from_binary(JidBIn), + Cols = ["nidx", "luser", "lserver", "aff"], + Vals = [Nidx, JID#jid.luser, JID#jid.lserver, mod_pubsub_db_rdbms:aff2int(H#pubsub_state.affiliation)], + Q = ["INSERT INTO pubsub_affiliations ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'pubsub_affiliations' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "pubsub_subscriptions" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_pubsub_subscriptions(Data :: list()) -> Result :: ok. + +migrate_pubsub_subscriptions([]) -> + ok; + +migrate_pubsub_subscriptions([H|_]) -> + case H#pubsub_state.subscriptions of + [{Type, SubID}] when Type =:= none; Type =:= pending; Type =:= subscribed -> + {SJID, Nidx} = H#pubsub_state.stateid, + JidBIn = jid:to_binary(SJID), + JID = jid:from_binary(JidBIn), + Cols = ["nidx", "luser", "lserver", "lresource", "type", "sub_id", "options"], + Vals = [Nidx, JID#jid.luser, JID#jid.lserver, JID#jid.lresource, + escape(mod_pubsub_db_rdbms:sub2int(Type)), SubID, "\"{}\""], + Q = ["INSERT INTO pubsub_subscriptions ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'pubsub_subscriptions' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end; + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "pubsub_items" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_pubsub_items(Data :: list()) -> Result :: ok. + +migrate_pubsub_items([]) -> + ok; + +migrate_pubsub_items([H|_]) -> + {IID, NodeIdx} = H#pubsub_item.itemid, + {CTime, CJID} = H#pubsub_item.creation, + [Payload] = H#pubsub_item.payload, + CT = to_unixtime(CTime), + JidBIn = jid:to_binary(CJID), + JID = jid:from_binary(JidBIn), + XMLB = <<"", (exml:to_binary(Payload))/binary, "">>, + Cols = ["nidx", "itemid", "created_luser", "created_lserver", "created_at", + "modified_luser", "modified_lserver", "modified_lresource", "modified_at", "payload"], + Vals = [NodeIdx, IID, JID#jid.luser, JID#jid.lserver, CT, JID#jid.lserver, + JID#jid.lserver, JID#jid.lresource, CT, XMLB], + Q = ["INSERT INTO pubsub_items ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'pubsub_items' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "vcard" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_vcard(Data :: list()) -> Result :: ok. + +migrate_vcard([]) -> + ok; + +migrate_vcard([H|_]) -> + {Luser, Lserver} = H#vcard.us, + Cols = ["username", "server", "vcard"], + Vals = [Luser, Lserver, exml:to_binary(H#vcard.vcard)], + Q = ["INSERT INTO vcard ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'vcard' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "vcard_search" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_vcard_search(Data :: list()) -> Result :: ok. + +migrate_vcard_search([]) -> + ok; + +migrate_vcard_search([H|_]) -> + {Luser, Lserver} = H#vcard_search.us, + Cols = ["username", "lusername", "server", "fn", "lfn", "family", "lfamily", "given", + "lgiven", "middle", "lmiddle", "nickname", "lnickname", "bday", "lbday", "ctry", + "lctry", "locality", "llocality", "email", "lemail", "orgname", "lorgname", "orgunit", + "lorgunit"], + Vals = [Luser, H#vcard_search.luser, Lserver, H#vcard_search.fn, H#vcard_search.lfn, + H#vcard_search.family, H#vcard_search.lfamily, H#vcard_search.given, H#vcard_search.lgiven, + H#vcard_search.middle, H#vcard_search.lmiddle, H#vcard_search.nickname, H#vcard_search.lnickname, + H#vcard_search.bday, H#vcard_search.lbday, H#vcard_search.ctry, H#vcard_search.lctry, + H#vcard_search.locality, H#vcard_search.llocality, H#vcard_search.email, H#vcard_search.lemail, + H#vcard_search.orgname, H#vcard_search.lorgname, H#vcard_search.orgunit, H#vcard_search.lorgunit], + Q = ["INSERT INTO vcard_search ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'vcard_search' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "users" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_users(Data :: list()) -> Result :: ok. + +migrate_users([]) -> + ok; + +migrate_users([H|_]) -> + Password = case ejabberd_auth_internal:get_password(H) of + P when is_binary(P) -> + P; + P -> + mongoose_scram:serialize(P) + end, + {Luser, _} = ejabberd_auth_internal:get_us(H), + Cols = ["username", "password"], + Vals = [Luser, Password], + Q = ["INSERT INTO users ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'users' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "event_pusher_push_subscription;" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_event_pusher_push_subscription(Data :: list()) -> Result :: ok. + +migrate_event_pusher_push_subscription([]) -> + ok; + +migrate_event_pusher_push_subscription([H|_]) -> + {Luser, Lserver} = mod_event_pusher_push_mnesia:get_user_jid(H), + Cols = ["owner_jid", "node", "pubsub_jid", "form", "created_at"], + Vals = [<>, mod_event_pusher_push_mnesia:get_pubsub_node(H), + jid:to_binary(mod_event_pusher_push_mnesia:get_pubsub_jid(H)), + jiffy:encode({mod_event_pusher_push_mnesia:get_form(H)}), + integer_to_binary(os:system_time(micro_seconds))], + Q = ["INSERT INTO event_pusher_push_subscription ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'event_pusher_push_subscription' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "rosterusers" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_rosterusers(Data :: list()) -> Result :: ok. + +migrate_rosterusers([]) -> + ok; + +migrate_rosterusers([H|_]) -> + {Luser, _} = H#roster.us, + Cols = ["username", "jid", "nick", "askmessage", "subscription", "ask", "server", "subscribe", "type"], + Vals = [Luser, jid:to_binary(H#roster.jid), H#roster.name, H#roster.askmessage, + subscription_to_char(H#roster.subscription), ask_to_char(H#roster.ask), + "", "", "item"], % @TODO what should be "server" - char(1)??? and what should be "subscribe" and "type" + Q = ["INSERT INTO rosterusers ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'rosterusers' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "roster_version" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_roster_version(Data :: list()) -> Result :: ok. + +migrate_roster_version([]) -> + ok; + +migrate_roster_version([H|_]) -> + {Luser, _} = H#roster_version.us, + Cols = ["username", "version"], + Vals = [Luser, H#roster_version.version], + Q = ["INSERT INTO roster_version ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'roster_version' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "rostergroups" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_rostergroups(Data :: list()) -> Result :: ok. + +migrate_rostergroups([]) -> + ok; + +migrate_rostergroups([H|_]) -> + {Luser, _} = H#roster.us, + Cols = ["username", "jid", "grp"], + Vals = [Luser, jid:to_binary(H#roster.jid)], + _ = [begin + Q = ["INSERT INTO rostergroups ", expand_sql_vals(Cols, Vals ++ [Group]), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'rostergroups' has error: ~p for values ~p", [Reason, Vals ++ Group]); + _ -> + ok + end + end || Group <- H#roster.groups], + ok. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "last" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_last(Data :: list()) -> Result :: ok. + +migrate_last([]) -> + ok; + +migrate_last([H|_]) -> + {Luser, _} = H#last_activity.us, + Cols = ["username", "seconds", "state"], + Vals = [Luser, H#last_activity.timestamp, H#last_activity.status], + Q = ["INSERT INTO last ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'last' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "private_storage" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_private_storage(Data :: list()) -> Result :: ok. + +migrate_private_storage([]) -> + ok; + +migrate_private_storage([H|_]) -> + {LUser, _, NS} = mod_private_mnesia:get_usns(H), + Cols = ["username", "namespace", "data"], + Vals = [LUser, NS, exml:to_binary(mod_private_mnesia:get_xml(H))], + Q = ["INSERT INTO private_storage ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'private_storage' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "offline_message" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_offline_message(Data :: list()) -> Result :: ok. + +migrate_offline_message([]) -> + ok; + +migrate_offline_message([H|_]) -> + {LUser, LServer} = H#offline_msg.us, + Cols = ["timestamp", "server", "username", "from_jid", "packet"], + Vals = [integer_to_binary(to_unixtime(H#offline_msg.timestamp)), LServer, + LUser, jid:to_binary(H#offline_msg.from), exml:to_binary(H#offline_msg.packet)], + Q = ["INSERT INTO offline_message ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'offline_message' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "muc_light_rooms" from Mnesia to SQL DB +%% @end +%% ------------------------------------------------------------------- +-spec migrate_muc_light_rooms(Data :: list()) -> Result :: ok. + +migrate_muc_light_rooms([]) -> + ok; + +migrate_muc_light_rooms([H|_]) -> + {LUser, LServer} = mod_muc_light_db_mnesia:get_room(H), + ID = case mongoose_rdbms:sql_query(?MYNAME, "SELECT MAX(ID) from muc_light_rooms;") of + {selected, [{null}]} -> + 1; + {selected, [{N}]} when is_integer(N) -> + N + 1 + end, + Cols = ["id", "luser", "lserver", "version"], + Vals = [ID, LUser, LServer, mod_muc_light_db_mnesia:get_room_version(H)], + Q = ["INSERT INTO muc_light_rooms ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'muc_light_rooms' has error: ~p for values ~p", [Reason, Vals]); + _ -> + migrate_muc_light_config(mod_muc_light_db_mnesia:get_room_config(H), ID), + _ = [migrate_muc_light_occupants(ID, U, S, Aff) || {{U, S}, Aff} <- mod_muc_light_db_mnesia:get_room_aff_users(H)], + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "muc_light_config" from Mnesia to SQL DB +%% For "muc_light_config" need to know "room_id", by this reason this function used inside of migrate_muc_light_rooms/1 +%% @end +%% ------------------------------------------------------------------- +-spec migrate_muc_light_config(Data :: list(), RoomID :: integer()) -> ok. + +migrate_muc_light_config([{_, Name}, {_, Subject}], RoomID) -> + Cols = ["room_id", "opt", "val"], + Vals = [RoomID, Name, Subject], + Q = ["INSERT INTO muc_light_config ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'muc_light_config' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Helper for migrate "muc_light_occupants" from Mnesia to SQL DB +%% For "muc_light_occupants" need to know "room_id", by this reason this function used inside of migrate_muc_light_rooms/1 +%% @end +%% ------------------------------------------------------------------- +-spec migrate_muc_light_occupants(ID :: integer(), U :: binary(), S :: binary(), A :: atom()) -> ok. + +migrate_muc_light_occupants(ID, LUser, LServer, Aff) -> + AffDB = case Aff of + owner -> + 1; + member -> + 2; + _ -> + 0 + end, + case AffDB of + 0 -> + ok; + AffDB -> + Cols = ["room_id", "luser", "lserver", "aff"], + Vals = [ID, LUser, LServer, AffDB], + Q = ["INSERT INTO muc_light_occupants ", expand_sql_vals(Cols, Vals), ";"], + case mongoose_rdbms:sql_query(?MYNAME, Q) of + {error, Reason} -> + ?WARNING_MSG("The SQL for 'migrate_muc_light_occupants' has error: ~p for values ~p", [Reason, Vals]); + _ -> + ok + end + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% convert time for DB +%% @end +%% ------------------------------------------------------------------- +-spec to_unixtime(Data :: tuple()) -> Result :: integer(). + +to_unixtime({Mega, Sec, Micro}) -> + Mega * 1000000 * 1000000 + Sec * 1000000 + Micro. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Getting data from table of Mnesia by table name +%% @end +%% ------------------------------------------------------------------- +-spec get_data(Step :: atom(), Name :: atom() | tuple()) -> Result :: {ok, any(), any()} | {error, list()}. + +get_data(first, Name) -> + try + Key = mnesia:dirty_first(Name), + {ok, mnesia:dirty_read(Name, Key), mnesia:dirty_next(Name, Key)} + catch Class:Exception -> + {error, io_lib:format("Migration call: [~p:~p/1] catched ~p:~p", [?MODULE, get_data, Class, Exception])} + end; + +get_data(next, {Name, Key}) -> + {ok, mnesia:dirty_read(Name, Key), mnesia:dirty_next(Name, Key)}. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Generate SQL values: "(field_1, field_1) VALUES ('bear', 'one')" +%% @end +%% ------------------------------------------------------------------- +-spec expand_sql_vals(Cols :: list(), Vals :: list()) -> Q :: list(). + +expand_sql_vals(Cols, Vals) -> + EVals = [escape(V) || V <- Vals], + ["(", join(Cols, ", "), ") VALUES (", join(EVals, ", "), ")"]. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Join lists by separator +%% @end +%% ------------------------------------------------------------------- +-spec join(list(), list()) -> list(). + +join([], _Sep) -> + []; + +join([H|T], Sep) -> + [H, [[Sep, X] || X <- T]]. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% escape helper +%% @end +%% ------------------------------------------------------------------- +-spec escape(Data :: any()) -> Res :: binary() | list() | any(). + +escape(Data) when is_integer(Data) -> + integer_to_binary(Data); + +escape(Data) when is_binary(Data); is_list(Data) -> + [$', mongoose_rdbms:escape_characters(Data), $']; + +escape(Data) -> + Data. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Subscription to char +%% @end +%% ------------------------------------------------------------------- +-spec subscription_to_char(Data :: atom()) -> Result :: binary(). + +subscription_to_char(Subs) -> + case Subs of + both -> + <<"B">>; + to -> + <<"T">>; + from -> + <<"F">>; + remove -> + <<"R">>; + none -> + <<"N">> + end. + +%% ------------------------------------------------------------------- +%% @private +%% @doc +%% Ask to char +%% @end +%% ------------------------------------------------------------------- +-spec ask_to_char(Data :: atom()) -> Result :: binary(). + +ask_to_char(Ask) -> + case Ask of + subscribe -> + <<"S">>; + unsubscribe -> + <<"U">>; + both -> + <<"B">>; + out -> + <<"O">>; + in -> + <<"I">>; + _ -> + <<"N">> + end. diff --git a/src/auth/ejabberd_auth_internal.erl b/src/auth/ejabberd_auth_internal.erl index 0e947618c56..ec8460fa7af 100644 --- a/src/auth/ejabberd_auth_internal.erl +++ b/src/auth/ejabberd_auth_internal.erl @@ -51,6 +51,8 @@ -export([check_password/3, check_password/5]). +-export([get_us/1, get_password/1]). + -include("mongoose.hrl"). -include("scram.hrl"). @@ -359,3 +361,11 @@ get_vh_registered_users_within_interval(Users, Limit, Offset) -> Length = length(Set), Start = min(1, max(Offset, Length)), lists:sublist(Set, Start, Limit). + +-spec get_us(Data :: passwd()) -> tuple(). +get_us(#passwd{us = US}) -> + US. + +-spec get_password(Data :: passwd()) -> tuple() | binary(). +get_password(#passwd{password = Pass}) -> + Pass. diff --git a/src/event_pusher/mod_event_pusher_push_mnesia.erl b/src/event_pusher/mod_event_pusher_push_mnesia.erl index 6d270972b35..d5146262f15 100644 --- a/src/event_pusher/mod_event_pusher_push_mnesia.erl +++ b/src/event_pusher/mod_event_pusher_push_mnesia.erl @@ -19,6 +19,7 @@ -export([init/2]). -export([enable/4, disable/3, get_publish_services/1]). +-export([get_user_jid/1, get_pubsub_jid/1, get_pubsub_node/1, get_form/1]). %%-------------------------------------------------------------------- %% Definitions @@ -148,3 +149,19 @@ make_record(UserJID, PubsubJID, Node, Form) -> -spec key(jid:jid()) -> key(). key(JID) -> jid:to_lus(JID). + +-spec get_user_jid(Data :: tuple()) -> Result :: key() | undefined. +get_user_jid(#push_subscription{user_jid = UserJid}) -> + UserJid. + +-spec get_pubsub_jid(Data :: tuple()) -> Result :: jid:jid(). +get_pubsub_jid(#push_subscription{pubsub_jid = PubsubJid}) -> + PubsubJid. + +-spec get_pubsub_node(Data :: tuple()) -> Result :: mod_event_pusher_push:pubsub_node(). +get_pubsub_node(#push_subscription{pubsub_node = PubsubNode}) -> + PubsubNode. + +-spec get_form(Data :: tuple()) -> Result :: mod_event_pusher_push:form(). +get_form(#push_subscription{form = Form}) -> + Form. diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl index ba76c990114..a26bc2a4ac0 100644 --- a/src/mod_private_mnesia.erl +++ b/src/mod_private_mnesia.erl @@ -37,6 +37,8 @@ -export([get_all_nss/2]). +-export([get_usns/1, get_xml/1]). + -include("mongoose.hrl"). -include("jlib.hrl"). @@ -98,3 +100,9 @@ select_namespaces_t(LUser, LServer) -> delete_record_t(LUser, LServer, NS) -> mnesia:delete({private_storage, {LUser, LServer, NS}}). + +get_usns(#private_storage{usns = USNS}) -> + USNS. + +get_xml(#private_storage{xml = XML}) -> + XML. diff --git a/src/muc_light/mod_muc_light_db_mnesia.erl b/src/muc_light/mod_muc_light_db_mnesia.erl index 09eb86122cd..17bf0223b1c 100644 --- a/src/muc_light/mod_muc_light_db_mnesia.erl +++ b/src/muc_light/mod_muc_light_db_mnesia.erl @@ -55,6 +55,8 @@ force_clear/0 ]). +-export([get_room/1, get_room_config/1, get_room_aff_users/1, get_room_version/1]). + -include("mongoose.hrl"). -include("jlib.hrl"). -include("mod_muc_light.hrl"). @@ -414,3 +416,18 @@ update_users_rooms(RoomUS, [], [User | RLeavingUsers]) -> update_users_rooms(_RoomUS, [], []) -> ok. +-spec get_room(Data :: muc_light_room()) -> jid:simple_bare_jid(). +get_room(#muc_light_room{room = Room}) -> + Room. + +-spec get_room_config(Data :: muc_light_room()) -> [{atom(), term()}]. +get_room_config(#muc_light_room{config = Config}) -> + Config. + +-spec get_room_aff_users(Data :: muc_light_room()) -> aff_users(). +get_room_aff_users(#muc_light_room{aff_users = AffUsers}) -> + AffUsers. + +-spec get_room_version(Data :: muc_light_room()) -> binary(). +get_room_version(#muc_light_room{version = Version}) -> + Version. diff --git a/src/rdbms/mongoose_rdbms.erl b/src/rdbms/mongoose_rdbms.erl index 4a461b8a2a5..3e2e4e215ff 100644 --- a/src/rdbms/mongoose_rdbms.erl +++ b/src/rdbms/mongoose_rdbms.erl @@ -88,7 +88,8 @@ %% Unicode escaping -export([escape_string/1, - use_escaped_string/1]). + use_escaped_string/1, + escape_characters/1]). %% Integer escaping -export([escape_integer/1,