diff --git a/big_tests/tests/graphql_session_SUITE.erl b/big_tests/tests/graphql_session_SUITE.erl index d67d4af521..e67eebd256 100644 --- a/big_tests/tests/graphql_session_SUITE.erl +++ b/big_tests/tests/graphql_session_SUITE.erl @@ -8,7 +8,8 @@ -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]). -import(domain_helper, [domain/0]). -import(graphql_helper, [execute_user_command/5, execute_command/4, get_listener_port/1, - get_listener_config/1, get_ok_value/2, get_err_msg/1, get_unauthorized/1]). + get_listener_config/1, get_ok_value/2, get_err_msg/1, get_unauthorized/1, + get_coercion_err_msg/1]). suite() -> require_rpc_nodes([mim]) ++ escalus:suite(). @@ -38,7 +39,8 @@ admin_session_tests() -> admin_get_user_resource, admin_list_users_with_status, admin_count_users_with_status, - admin_kick_session, + admin_kick_user_session, + admin_kick_user, admin_set_presence, admin_set_presence_away, admin_set_presence_unavailable]. @@ -54,7 +56,8 @@ domain_admin_session_tests() -> domain_admin_get_user_resource_no_permission, domain_admin_list_users_with_status, domain_admin_count_users_with_status, - admin_kick_session, + admin_kick_user_session, + domain_admin_kick_user_session_no_permission, domain_admin_kick_user_no_permission, admin_set_presence, admin_set_presence_away, @@ -197,12 +200,22 @@ domain_admin_get_user_resource_story_no_permission_story(Config, AliceBis) -> Res = get_user_resource(AliceBisJID, 2, Config), get_unauthorized(Res). +domain_admin_kick_user_session_no_permission(Config) -> + escalus:fresh_story_with_config(Config, [{alice_bis, 1}], + fun domain_admin_kick_user_session_no_permission_story/2). + +domain_admin_kick_user_session_no_permission_story(Config, AliceBis) -> + AliceBisJID = escalus_client:full_jid(AliceBis), + Reason = <<"Test kick">>, + Res = kick_user_session(AliceBisJID, Reason, Config), + get_unauthorized(Res). + domain_admin_kick_user_no_permission(Config) -> escalus:fresh_story_with_config(Config, [{alice_bis, 1}], fun domain_admin_kick_user_no_permission_story/2). domain_admin_kick_user_no_permission_story(Config, AliceBis) -> - AliceBisJID = escalus_client:full_jid(AliceBis), + AliceBisJID = escalus_client:short_jid(AliceBis), Reason = <<"Test kick">>, Res = kick_user(AliceBisJID, Reason, Config), get_unauthorized(Res). @@ -290,7 +303,10 @@ admin_list_sessions_story(Config, _Alice, AliceB, _Bob) -> ?assertEqual(1, length(Sessions2)), Res3 = list_sessions(unprep(BisDomain), Config), Sessions3 = get_ok_value(Path, Res3), - ?assertEqual(1, length(Sessions3)). + ?assertEqual(1, length(Sessions3)), + % List sessions for a non-existing domain + Res4 = list_sessions(<<"nonexisting">>, Config), + ?assertEqual(<<"Domain not found">>, get_err_msg(Res4)). admin_count_sessions(Config) -> escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}], @@ -307,7 +323,10 @@ admin_count_sessions_story(Config, _Alice, AliceB, _Bob) -> Res2 = count_sessions(BisDomain, Config), ?assertEqual(1, get_ok_value(Path, Res2)), Res3 = count_sessions(unprep(BisDomain), Config), - ?assertEqual(1, get_ok_value(Path, Res3)). + ?assertEqual(1, get_ok_value(Path, Res3)), + % Count sessions for a non-existing domain + Res4 = count_sessions(<<"nonexisting">>, Config), + ?assertEqual(<<"Domain not found">>, get_err_msg(Res4)). admin_list_user_sessions(Config) -> escalus:fresh_story_with_config(Config, [{alice, 2}, {bob, 1}], @@ -321,7 +340,11 @@ admin_list_user_sessions_story(Config, Alice, Alice2, _Bob) -> ExpectedRes = lists:map(fun escalus_utils:jid_to_lower/1, [S1JID, S2JID]), Sessions = get_ok_value(Path, Res), ?assertEqual(2, length(Sessions)), - check_users(ExpectedRes, Sessions). + check_users(ExpectedRes, Sessions), + % Check for a non-existing user + Domain = domain(), + Res2 = list_user_sessions(<<"alien@", Domain/binary>>, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)). admin_count_user_resources(Config) -> escalus:fresh_story_with_config(Config, [{alice, 3}], fun admin_count_user_resources_story/4). @@ -330,7 +353,11 @@ admin_count_user_resources_story(Config, Alice, _Alice2, _Alice3) -> Path = [data, session, countUserResources], JID = escalus_client:full_jid(Alice), Res = count_user_resources(JID, Config), - ?assertEqual(3, get_ok_value(Path, Res)). + ?assertEqual(3, get_ok_value(Path, Res)), + % Check for a non-existing user + Domain = domain(), + Res2 = count_user_resources(<<"alien@", Domain/binary>>, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)). admin_get_user_resource(Config) -> escalus:fresh_story_with_config(Config, [{alice, 3}], fun admin_get_user_resource_story/4). @@ -343,7 +370,11 @@ admin_get_user_resource_story(Config, Alice, Alice2, _Alice3) -> ?assertEqual(escalus_client:resource(Alice2), get_ok_value(Path, Res)), % Provide a wrong resource number Res2 = get_user_resource(JID, 4, Config), - ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"Wrong resource number">>)). + ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"Wrong resource number">>)), + % Check for a non-existing user + Domain = domain(), + Res3 = get_user_resource(<<"alien@", Domain/binary>>, 1, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res3)). admin_count_users_with_status(Config) -> escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}], @@ -363,7 +394,10 @@ admin_count_users_with_status_story(Config, Alice, AliceB) -> assert_count_users_with_status(1, unprep(domain_helper:domain()), AwayStatus, Config), % Count users with dnd status globally escalus_client:send(AliceB, DndPresence), - assert_count_users_with_status(1, null, DndStatus, Config). + assert_count_users_with_status(1, null, DndStatus, Config), + % Count users with dnd status for a non-existing domain + Res = count_users_with_status(<<"nonexisting">>, DndStatus, Config), + ?assertEqual(<<"Domain not found">>, get_err_msg(Res)). admin_list_users_with_status(Config) -> escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}], @@ -385,29 +419,51 @@ admin_list_users_with_status_story(Config, Alice, AliceB) -> assert_list_users_with_status([AliceJID], unprep(domain()), AwayStatus, Config), % List users with dnd status globally escalus_client:send(AliceB, DndPresence), - assert_list_users_with_status([AliceBJID], null, DndStatus, Config). + assert_list_users_with_status([AliceBJID], null, DndStatus, Config), + % List users with dnd status for a non-existing domain + Res = count_users_with_status(<<"nonexisting">>, DndStatus, Config), + ?assertEqual(<<"Domain not found">>, get_err_msg(Res)). -admin_kick_session(Config) -> - escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_kick_session_story/3). +admin_kick_user_session(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_kick_user_session_story/3). -admin_kick_session_story(Config, Alice1, Alice2) -> +admin_kick_user_session_story(Config, Alice1, Alice2) -> JIDA1 = escalus_client:full_jid(Alice1), JIDA2 = escalus_client:full_jid(Alice2), Reason = <<"Test kick">>, - Path = [data, session, kickUser, message], - Res = kick_user(JIDA1, Reason, Config), + Path = [data, session, kickUserSession, message], + Res = kick_user_session(JIDA1, Reason, Config), % Kick an active session ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res), <<"kicked">>)), - ?assertEqual(JIDA1, get_ok_value([data, session, kickUser, jid], Res)), + ?assertEqual(JIDA1, get_ok_value([data, session, kickUserSession, jid], Res)), % Try to kick an offline session - Res2 = kick_user(JIDA1, Reason, Config), + Res2 = kick_user_session(JIDA1, Reason, Config), ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"No active session">>)), % Try to kick a session with JID without a resource - Res3 = kick_user(escalus_client:short_jid(Alice2), Reason, Config), - ?assertNotEqual(nomatch, binary:match(get_err_msg(Res3), <<"No active session">>)), - % Kick another active session - Res4 = kick_user(JIDA2, Reason, Config), - ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res4), <<"kicked">>)). + Res3 = kick_user_session(escalus_client:short_jid(Alice2), Reason, Config), + ?assertNotEqual(nomatch, binary:match(get_coercion_err_msg(Res3), <<"jid_without_resource">>)), + % Kick active session without reason text + Res4 = kick_user_session(JIDA2, null, Config), + ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res4), <<"kicked">>)), + % Kick a non-existing user + Domain = domain(), + Res5 = kick_user_session(<<"alien@", Domain/binary, "/mobile">>, null, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res5)). + +admin_kick_user(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_kick_user_story/3). + +admin_kick_user_story(Config, Alice1, _Alice2) -> + AliceJID = escalus_client:short_jid(Alice1), + Reason = <<"Test kick">>, + Res1 = kick_user(AliceJID, Reason, Config), + Res2 = get_ok_value([data, session, kickUser], Res1), + ?assertEqual(2, length(Res2)), + ?assertEqual([true, true], [Kicked || #{<<"kicked">> := Kicked} <- Res2]), + % Kick a non-existing user + Domain = domain(), + Res5 = kick_user(<<"alien@", Domain/binary>>, null, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res5)). admin_set_presence(Config) -> escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_set_presence_story/2). @@ -422,10 +478,14 @@ admin_set_presence_story(Config, Alice) -> % Send short JID Res = set_presence(ShortJID, Type, Show, Status, Priority, Config), ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"resource is empty">>)), + % Non-existing user + Domain = domain(), + Res2 = set_presence(<<"alien@", Domain/binary, "/mobile">>, Type, Show, Status, Priority, Config), + ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)), % Send full JID Path = [data, session, setPresence, message], - Res2 = set_presence(JID, Type, Show, Status, Priority, Config), - ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res2), <<"set successfully">>)), + Res3 = set_presence(JID, Type, Show, Status, Priority, Config), + ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res3), <<"set successfully">>)), Presence = escalus:wait_for_stanza(Alice), ?assertNot(escalus_pred:is_presence_with_show(<<"online">>, Presence)), escalus:assert(is_presence_with_type, [<<"available">>], Presence), @@ -500,6 +560,10 @@ count_users_with_status(Domain, Status, Config) -> Vars = #{<<"domain">> => Domain, <<"status">> => Status}, execute_command(<<"session">>, <<"countUsersWithStatus">>, Vars, Config). +kick_user_session(JID, Reason, Config) -> + Vars = #{<<"user">> => JID, <<"reason">> => Reason}, + execute_command(<<"session">>, <<"kickUserSession">>, Vars, Config). + kick_user(JID, Reason, Config) -> Vars = #{<<"user">> => JID, <<"reason">> => Reason}, execute_command(<<"session">>, <<"kickUser">>, Vars, Config). diff --git a/priv/graphql/schemas/admin/session.gql b/priv/graphql/schemas/admin/session.gql index 5782e4bd07..c353ea4ba4 100644 --- a/priv/graphql/schemas/admin/session.gql +++ b/priv/graphql/schemas/admin/session.gql @@ -15,13 +15,13 @@ type SessionAdminQuery @protected{ countUserResources(user: JID!): Int @protected(type: DOMAIN, args: ["user"]) "Get the resource string of the n-th session of a user" - getUserResource(user: JID!, number: Int): ResourceName + getUserResource(user: JID!, number: PosInt!): ResourceName @protected(type: DOMAIN, args: ["user"]) "Get the list of logged users with this status for a specified domain or globally" - listUsersWithStatus(domain: DomainName, status: String!): [UserStatus!] + listUsersWithStatus(domain: DomainName, status: NonEmptyString!): [UserStatus!] @protected(type: DOMAIN, args: ["domain"]) "Get the number of logged users with this status for a specified domain or globally" - countUsersWithStatus(domain: DomainName, status: String!): Int + countUsersWithStatus(domain: DomainName, status: NonEmptyString!): Int @protected(type: DOMAIN, args: ["domain"]) } @@ -29,8 +29,11 @@ type SessionAdminQuery @protected{ Allow admin to manage sessions. """ type SessionAdminMutation @protected{ - "Kick a user session. User JID should contain resource" - kickUser(user: JID!, reason: String!): SessionPayload + "Kick a user session. User JID must contain resource" + kickUserSession(user: FullJID!, reason: String): KickUserResult + @protected(type: DOMAIN, args: ["user"]) + "Kick user sessions" + kickUser(user: BareJID!, reason: String): [KickUserResult!] @protected(type: DOMAIN, args: ["user"]) "Set presence of a session. User JID should contain resource" setPresence(user: JID!, type: PresenceType!, show: PresenceShow, status: String, priority: Int): SessionPayload @@ -71,6 +74,18 @@ enum PresenceShow{ XA } +"Kick user session result" +type KickUserResult { + "Full JID with username, server and resource" + jid: JID! + "Result status" + kicked: Boolean! + "Result code (if failed)" + code: String + "Result message" + message: String! +} + "Modify session payload" type SessionPayload{ "Full JID with username, server and resource" diff --git a/src/admin_extra/service_admin_extra_accounts.erl b/src/admin_extra/service_admin_extra_accounts.erl index 108aa35d11..8e0d875b43 100644 --- a/src/admin_extra/service_admin_extra_accounts.erl +++ b/src/admin_extra/service_admin_extra_accounts.erl @@ -146,7 +146,7 @@ delete_old_users_for_domain(Domain, Days) -> Error end. --spec ban_account(jid:user(), jid:server(), binary() | string()) -> +-spec ban_account(jid:user(), jid:server(), binary()) -> mongoose_account_api:change_password_result(). ban_account(User, Host, ReasonText) -> mongoose_account_api:ban_account(User, Host, ReasonText). diff --git a/src/admin_extra/service_admin_extra_sessions.erl b/src/admin_extra/service_admin_extra_sessions.erl index 959fec65e8..b36fd5bdb1 100644 --- a/src/admin_extra/service_admin_extra_sessions.erl +++ b/src/admin_extra/service_admin_extra_sessions.erl @@ -28,10 +28,8 @@ -export([ commands/0, - num_resources/2, resource_num/3, - kick_session/2, kick_session/4, status_num/2, status_num/1, status_list/2, status_list/1, @@ -42,12 +40,13 @@ ]). -ignore_xref([ - commands/0, num_resources/2, resource_num/3, kick_session/2, kick_session/4, + commands/0, num_resources/2, resource_num/3, kick_session/4, status_num/2, status_num/1, status_list/2, status_list/1, connected_users_info/0, connected_users_info/1, set_presence/7, user_sessions_info/2 ]). +-include_lib("jid/include/jid.hrl"). -include("ejabberd_commands.hrl"). -type status() :: mongoose_session_api:status(). @@ -67,8 +66,16 @@ commands() -> {priority, integer}, {node, string}, {uptime, integer} - ]}} - }, + ]}}}, + + UserStatusDisplay = {list, + {userstatus, {tuple, + [{user, string}, + {host, string}, + {resource, string}, + {priority, integer}, + {status, string} + ]}}}, [ #ejabberd_commands{name = num_resources, tags = [session], @@ -86,7 +93,7 @@ commands() -> module = ?MODULE, function = kick_session, args = [{user, binary}, {host, binary}, {resource, binary}, {reason, binary}], - result = {res, restuple}}, + result = {res, integer}}, #ejabberd_commands{name = status_num_host, tags = [session, stats], desc = "Number of logged users with this status in host", module = ?MODULE, function = status_num, @@ -101,28 +108,12 @@ commands() -> desc = "List of users logged in host with their statuses", module = ?MODULE, function = status_list, args = [{host, binary}, {status, binary}], - result = {users, {list, - {userstatus, {tuple, [ - {user, string}, - {host, string}, - {resource, string}, - {priority, integer}, - {status, string} - ]}} - }}}, + result = {users, UserStatusDisplay}}, #ejabberd_commands{name = status_list, tags = [session], desc = "List of logged users with this status", module = ?MODULE, function = status_list, args = [{status, binary}], - result = {users, {list, - {userstatus, {tuple, [ - {user, string}, - {host, string}, - {resource, string}, - {priority, integer}, - {status, string} - ]}} - }}}, + result = {users, UserStatusDisplay}}, #ejabberd_commands{name = connected_users_info, tags = [session], desc = "List all established sessions and their information", @@ -159,52 +150,80 @@ commands() -> -spec num_resources(jid:user(), jid:server()) -> non_neg_integer(). num_resources(User, Host) -> - mongoose_session_api:num_resources(User, Host). + JID = jid:make(User, Host, <<>>), + {ok, Value} = mongoose_session_api:num_resources(JID), + Value. -spec resource_num(jid:user(), jid:server(), integer()) -> mongoose_session_api:res_number_result(). resource_num(User, Host, Num) -> - mongoose_session_api:get_user_resource(User, Host, Num). - --spec kick_session(jid:jid(), binary()) -> mongoose_session_api:kick_session_result(). -kick_session(JID, ReasonText) -> - mongoose_session_api:kick_session(JID, ReasonText). + JID = jid:make(User, Host, <<>>), + mongoose_session_api:get_user_resource(JID, Num). -spec kick_session(jid:user(), jid:server(), jid:resource(), binary()) -> mongoose_session_api:kick_session_result(). kick_session(User, Server, Resource, ReasonText) -> - mongoose_session_api:kick_session(User, Server, Resource, ReasonText). + mongoose_session_api:kick_session(jid:make(User, Server, Resource), ReasonText). -spec status_num(jid:server(), status()) -> non_neg_integer(). status_num(Host, Status) -> - mongoose_session_api:num_status_users(Host, Status). + {ok, Value} = mongoose_session_api:num_status_users(Host, Status), + Value. -spec status_num(status()) -> non_neg_integer(). status_num(Status) -> - mongoose_session_api:num_status_users(Status). + {ok, Value} = mongoose_session_api:num_status_users(Status), + Value. --spec status_list(jid:server(), status()) -> [mongoose_session_api:status_user_info()]. +-spec status_list(jid:server(), status()) -> [tuple()]. status_list(Host, Status) -> - mongoose_session_api:list_status_users(Host, Status). + {ok, Sessions} = mongoose_session_api:list_status_users(Host, Status), + format_status_users(Sessions). --spec status_list(binary()) -> [mongoose_session_api:status_user_info()]. +-spec status_list(binary()) -> [tuple()]. status_list(Status) -> - mongoose_session_api:list_status_users(Status). + {ok, Sessions} = mongoose_session_api:list_status_users(Status), + format_status_users(Sessions). --spec connected_users_info() -> mongoose_session_api:list_sessions_result(). +-spec connected_users_info() -> [tuple()]. connected_users_info() -> - mongoose_session_api:list_sessions(). + {ok, Sessions} = mongoose_session_api:list_sessions(), + format_sessions(Sessions). --spec connected_users_info(jid:server()) -> mongoose_session_api:list_sessions_result(). +-spec connected_users_info(jid:server()) -> [tuple()]. connected_users_info(Host) -> - mongoose_session_api:list_sessions(Host). + {ok, Sessions} = mongoose_session_api:list_sessions(Host), + format_sessions(Sessions). -spec set_presence(jid:user(), jid:server(), jid:resource(), Type :: binary(), Show :: binary(), Status :: binary(), Prio :: binary()) -> ok. set_presence(User, Host, Resource, Type, Show, Status, Priority) -> - mongoose_session_api:set_presence(User, Host, Resource, Type, Show, Status, Priority), + JID = jid:make(User, Host, Resource), + mongoose_session_api:set_presence(JID, Type, Show, Status, Priority), ok. --spec user_sessions_info(jid:user(), jid:server()) -> [mongoose_session_api:session_info()]. +-spec user_sessions_info(jid:user(), jid:server()) -> [tuple()]. user_sessions_info(User, Host) -> - mongoose_session_api:list_user_sessions(User, Host). + JID = jid:make(User, Host, <<>>), + {ok, Sessions} = mongoose_session_api:list_user_sessions(JID), + format_sessions(Sessions). + +% Internal + +format_sessions(Sessions) -> + lists:map(fun(S) -> format_session(S) end, Sessions). + +format_session({USR, Conn, Address, Prio, Node, Uptime}) -> + {IP, Port} = from_address(Address), + {jid:to_binary(USR), atom_to_list(Conn), IP, Port, Prio, atom_to_list(Node), Uptime}. + +from_address(undefined) -> + {undefined, undefined}; +from_address({IP, Port}) -> + {inet:ntoa(IP), Port}. + +format_status_users(Sessions) -> + lists:map(fun(S) -> format_status_user(S) end, Sessions). + +format_status_user({#jid{luser = User, lserver = Server, lresource = Resource}, Prio, Status}) -> + {User, Server, Resource, Prio, Status}. diff --git a/src/graphql/admin/mongoose_graphql_session_admin_mutation.erl b/src/graphql/admin/mongoose_graphql_session_admin_mutation.erl index 64e13fa6e1..5c7610c7b3 100644 --- a/src/graphql/admin/mongoose_graphql_session_admin_mutation.erl +++ b/src/graphql/admin/mongoose_graphql_session_admin_mutation.erl @@ -9,15 +9,26 @@ -import(mongoose_graphql_helper, [make_error/2]). +execute(_Ctx, _Obj, <<"kickUserSession">>, Args) -> + kick_user_session(Args); execute(_Ctx, _Obj, <<"kickUser">>, Args) -> kick_user(Args); execute(_Ctx, _Obj, <<"setPresence">>, Args) -> set_presence(Args). --spec kick_user(map()) -> {ok, map()} | {error, resolver_error()}. +-spec kick_user_session(map()) -> {ok, mongoose_session_api:kick_user_result()} | {error, resolver_error()}. +kick_user_session(#{<<"user">> := JID, <<"reason">> := KickReason}) -> + case mongoose_session_api:kick_session(JID, KickReason) of + {ok, Result} -> {ok, Result}; + Error -> make_error(Error, #{jid => jid:to_binary(JID), reason => KickReason}) + end. + +-spec kick_user(map()) -> {ok, [mongoose_session_api:kick_user_result()]} | {error, resolver_error()}. kick_user(#{<<"user">> := JID, <<"reason">> := KickReason}) -> - Result = mongoose_session_api:kick_session(JID, KickReason), - format_session_payload(Result, JID). + case mongoose_session_api:kick_sessions(JID, KickReason) of + {ok, Result} -> {ok, Result}; + Error -> make_error(Error, #{jid => jid:to_binary(JID), reason => KickReason}) + end. -spec set_presence(map()) -> {ok, map()} | {error, resolver_error()}. set_presence(#{<<"user">> := JID, <<"type">> := Type, @@ -43,7 +54,7 @@ format_session_payload(InResult, JID) -> {ok, Msg} -> {ok, make_session_payload(Msg, JID)}; Result -> - make_error(Result, #{jid => JID}) + make_error(Result, #{jid => jid:to_binary(JID)}) end. -spec make_session_payload(binary(), jid:jid()) -> map(). diff --git a/src/graphql/admin/mongoose_graphql_session_admin_query.erl b/src/graphql/admin/mongoose_graphql_session_admin_query.erl index 2dca3c5a18..ba051cd745 100644 --- a/src/graphql/admin/mongoose_graphql_session_admin_query.erl +++ b/src/graphql/admin/mongoose_graphql_session_admin_query.erl @@ -5,8 +5,10 @@ -ignore_xref([execute/4]). +-include("../mongoose_graphql_types.hrl"). + -import(mongoose_graphql_session_helper, [format_sessions/1, format_status_users/1]). --import(mongoose_graphql_helper, [format_result/2]). +-import(mongoose_graphql_helper, [format_result/2, make_error/2]). execute(_Ctx, _Obj, <<"listSessions">>, Args) -> list_sessions(Args); @@ -23,47 +25,57 @@ execute(_Ctx, _Obj, <<"listUsersWithStatus">>, Args) -> execute(_Ctx, _Obj, <<"countUsersWithStatus">>, Args) -> count_users_with_status(Args). --spec list_sessions(map()) -> {ok, mongoose_graphql_session_helper:session_list()}. +-spec list_sessions(map()) -> {ok, mongoose_graphql_session_helper:session_list()} | {error, resolver_error()}. list_sessions(#{<<"domain">> := null}) -> - Sessions = mongoose_session_api:list_sessions(), + {ok, Sessions} = mongoose_session_api:list_sessions(), {ok, format_sessions(Sessions)}; list_sessions(#{<<"domain">> := Domain}) -> - Sessions = mongoose_session_api:list_sessions(Domain), - {ok, format_sessions(Sessions)}. + case mongoose_session_api:list_sessions(Domain) of + {ok, Sessions} -> + {ok, format_sessions(Sessions)}; + Error -> + make_error(Error, #{domain => Domain}) + end. --spec count_sessions(map()) -> {ok, non_neg_integer()}. +-spec count_sessions(map()) -> {ok, non_neg_integer()} | {error, resolver_error()}. count_sessions(#{<<"domain">> := null}) -> - {ok, mongoose_session_api:count_sessions()}; + mongoose_session_api:count_sessions(); count_sessions(#{<<"domain">> := Domain}) -> - {ok, mongoose_session_api:count_sessions(Domain)}. + format_result(mongoose_session_api:count_sessions(Domain), #{domain => Domain}). -spec list_user_sessions(map()) -> {ok, mongoose_graphql_session_helper:session_list()}. list_user_sessions(#{<<"user">> := JID}) -> - Sessions = mongoose_session_api:list_user_sessions(JID), - {ok, format_sessions(Sessions)}. + case mongoose_session_api:list_user_sessions(JID) of + {ok, Sessions} -> + {ok, format_sessions(Sessions)}; + Error -> + make_error(Error, #{user => jid:to_binary(JID)}) + end. --spec count_user_resources(map()) -> {ok, non_neg_integer()}. +-spec count_user_resources(map()) -> {ok, non_neg_integer()} | {error, resolver_error()}. count_user_resources(#{<<"user">> := JID}) -> - Number = mongoose_session_api:num_resources(JID), - {ok, Number}. + format_result(mongoose_session_api:num_resources(JID), #{jid => jid:to_binary(JID)}). --spec get_user_resource(map()) -> {ok, jid:lresource()}. +-spec get_user_resource(map()) -> {ok, jid:lresource()} | {error, resolver_error()}. get_user_resource(#{<<"user">> := JID, <<"number">> := ResNumber}) -> Result = mongoose_session_api:get_user_resource(JID, ResNumber), - format_result(Result, #{number => ResNumber}). + format_result(Result, #{user => jid:to_binary(JID), number => ResNumber}). --spec list_users_with_status(map()) -> {ok, mongoose_graphql_session_helper:status_user_list()}. +-spec list_users_with_status(map()) -> {ok, mongoose_graphql_session_helper:status_user_list()} + | {error, resolver_error()}. list_users_with_status(#{<<"domain">> := null, <<"status">> := Status}) -> - StatusUsers = mongoose_session_api:list_status_users(Status), + {ok, StatusUsers} = mongoose_session_api:list_status_users(Status), {ok, format_status_users(StatusUsers)}; list_users_with_status(#{<<"domain">> := Domain, <<"status">> := Status}) -> - StatusUsers = mongoose_session_api:list_status_users(Domain, Status), - {ok, format_status_users(StatusUsers)}. + case mongoose_session_api:list_status_users(Domain, Status) of + {ok, StatusUsers} -> + {ok, format_status_users(StatusUsers)}; + Error -> + make_error(Error, #{domain => Domain, status => Status}) + end. --spec count_users_with_status(map()) -> {ok, non_neg_integer()}. +-spec count_users_with_status(map()) -> {ok, non_neg_integer()} | {error, resolver_error()}. count_users_with_status(#{<<"domain">> := null, <<"status">> := Status}) -> - Number = mongoose_session_api:num_status_users(Status), - {ok, Number}; + format_result(mongoose_session_api:num_status_users(Status), #{status => Status}); count_users_with_status(#{<<"domain">> := Domain, <<"status">> := Status}) -> - Number = mongoose_session_api:num_status_users(Domain, Status), - {ok, Number}. + format_result(mongoose_session_api:num_status_users(Domain, Status), #{domain => Domain, status => Status}). diff --git a/src/graphql/mongoose_graphql_muc_helper.erl b/src/graphql/mongoose_graphql_muc_helper.erl index 447d65a053..0f1130d59d 100644 --- a/src/graphql/mongoose_graphql_muc_helper.erl +++ b/src/graphql/mongoose_graphql_muc_helper.erl @@ -13,13 +13,15 @@ -include("mod_muc_room.hrl"). -spec add_user_resource(jid:jid(), binary() | null) -> - {ok, jid:jid()} | {no_session, iolist()}. + {ok, jid:jid()} | {atom(), binary()}. add_user_resource(JID, null) -> case mongoose_session_api:get_user_resource(JID, 1) of {ok, Resource} -> {ok, jid:replace_resource(JID, Resource)}; - {wrong_res_number, _ErrMsg}-> - {no_session, "Given user does not have any session"} + {wrong_res_number, _} -> + {no_session, <<"Given user does not have any session">>}; + Error -> + Error end; add_user_resource(JID, Resource) -> {ok, jid:replace_resource(JID, Resource)}. diff --git a/src/graphql/mongoose_graphql_session_helper.erl b/src/graphql/mongoose_graphql_session_helper.erl index ec0412c3b3..c503325ad6 100644 --- a/src/graphql/mongoose_graphql_session_helper.erl +++ b/src/graphql/mongoose_graphql_session_helper.erl @@ -16,21 +16,30 @@ format_sessions(Sessions) -> lists:map(fun(S) -> {ok, format_session(S)} end, Sessions). -spec format_session(mongoose_session_api:session_info()) -> session_data(). -format_session({USR, Conn, IPS, PORT, Prio, NodeS, Uptime}) -> - #{<<"user">> => iolist_to_binary(USR), - <<"connection">> => iolist_to_binary(Conn), - <<"ip">> => iolist_to_binary(IPS), - <<"port">> => PORT, +format_session({USR, Conn, Address, Prio, Node, Uptime}) -> + {IP, Port} = from_address(Address), + #{<<"user">> => jid:to_binary(USR), + <<"connection">> => from_conn(Conn), + <<"ip">> => IP, + <<"port">> => Port, <<"priority">> => Prio, - <<"node">> => iolist_to_binary(NodeS), + <<"node">> => atom_to_binary(Node), <<"uptime">> => Uptime}. --spec format_status_users([mongoose_session_api:session_info()]) -> session_list(). +from_conn(undefined) -> null; +from_conn(Conn) -> atom_to_binary(Conn). + +from_address(undefined) -> + {null, null}; +from_address({IP, Port}) -> + {iolist_to_binary(inet:ntoa(IP)), Port}. + +-spec format_status_users([mongoose_session_api:status_user_info()]) -> status_user_list(). format_status_users(Sessions) -> lists:map(fun(S) -> {ok, format_status_user(S)} end, Sessions). -spec format_status_user(mongoose_session_api:status_user_info()) -> status_user_data(). -format_status_user({User, Server, Res, Prio, StatusText}) -> - #{<<"user">> => jid:to_binary({User, Server, Res}), +format_status_user({JID, Prio, StatusText}) -> + #{<<"user">> => jid:to_binary(JID), <<"priority">> => Prio, <<"text">> => iolist_to_binary(StatusText)}. diff --git a/src/graphql/user/mongoose_graphql_session_user_query.erl b/src/graphql/user/mongoose_graphql_session_user_query.erl index 381ca0576a..09d380e32b 100644 --- a/src/graphql/user/mongoose_graphql_session_user_query.erl +++ b/src/graphql/user/mongoose_graphql_session_user_query.erl @@ -14,17 +14,15 @@ execute(Ctx, _Obj, <<"listSessions">>, Args) -> -spec list_resources(map(), map()) -> {ok, [jid:lresource()]}. list_resources(#{user := JID}, _Args) -> - Resources = mongoose_session_api:list_user_resources(JID), - Result = lists:map(fun(R) -> {ok, R} end, Resources), - {ok, Result}. + {ok, Resources} = mongoose_session_api:list_user_resources(JID), + {ok, lists:map(fun(R) -> {ok, R} end, Resources)}. -spec count_resources(map(), map()) -> {ok, non_neg_integer()}. count_resources(#{user := JID}, _Args) -> - Number = length(mongoose_session_api:list_user_resources(JID)), - {ok, Number}. + {ok, Resources} = mongoose_session_api:list_user_resources(JID), + {ok, length(Resources)}. -spec list_sessions_info(map(), map()) -> {ok, mongoose_graphql_session_helper:session_list()}. list_sessions_info(#{user := JID}, _Args) -> - Sessions = mongoose_session_api:list_user_sessions(JID), - Result = mongoose_graphql_session_helper:format_sessions(Sessions), - {ok, Result}. + {ok, Sessions} = mongoose_session_api:list_user_sessions(JID), + {ok, mongoose_graphql_session_helper:format_sessions(Sessions)}. diff --git a/src/mongoose_account_api.erl b/src/mongoose_account_api.erl index d2f2cdb161..eec738a827 100644 --- a/src/mongoose_account_api.erl +++ b/src/mongoose_account_api.erl @@ -190,10 +190,9 @@ ban_account(User, Host, ReasonText) -> ban_account(JID, ReasonText). -spec ban_account(jid:jid(), binary()) -> change_password_result(). -ban_account(JID, ReasonText) -> +ban_account(JID, Reason) -> case ejabberd_auth:does_user_exist(JID) of true -> - Reason = mongoose_session_api:prepare_reason(ReasonText), mongoose_session_api:kick_sessions(JID, Reason), case set_random_password(JID, Reason) of ok -> diff --git a/src/mongoose_admin_api/mongoose_admin_api_sessions.erl b/src/mongoose_admin_api/mongoose_admin_api_sessions.erl index 2da78694eb..074f6fc8df 100644 --- a/src/mongoose_admin_api/mongoose_admin_api_sessions.erl +++ b/src/mongoose_admin_api/mongoose_admin_api_sessions.erl @@ -55,14 +55,14 @@ delete_resource(Req, State) -> handle_get(Req, State) -> #{domain := Domain} = cowboy_req:bindings(Req), - Sessions = mongoose_session_api:list_resources(Domain), + {ok, Sessions} = mongoose_session_api:list_resources(Domain), {jiffy:encode(Sessions), Req, State}. handle_delete(Req, State) -> #{domain := Domain} = Bindings = cowboy_req:bindings(Req), UserName = get_user_name(Bindings), Resource = get_resource(Bindings), - case mongoose_session_api:kick_session(UserName, Domain, Resource, <<"kicked">>) of + case mongoose_session_api:kick_session(jid:make(UserName, Domain, Resource), <<"kicked">>) of {ok, _} -> {true, Req, State}; {no_session, Reason} -> diff --git a/src/mongoose_session_api.erl b/src/mongoose_session_api.erl index 65ef45aaca..d7da1dd785 100644 --- a/src/mongoose_session_api.erl +++ b/src/mongoose_session_api.erl @@ -6,21 +6,16 @@ count_sessions/0, count_sessions/1, list_user_sessions/1, - list_user_sessions/2, list_resources/1, list_user_resources/1, num_resources/1, - num_resources/2, get_user_resource/2, - get_user_resource/3, list_status_users/1, list_status_users/2, num_status_users/1, num_status_users/2, - set_presence/7, set_presence/5, kick_session/2, - kick_session/4, kick_sessions/2, prepare_reason/1]). @@ -35,173 +30,224 @@ -type status() :: binary(). -type session() :: #session{}. --type status_user_info() :: {User :: jid:user(), - Server :: jid:server(), - Res :: jid:resource(), +-type status_user_info() :: {JID :: jid:jid(), Prio :: ejabberd_sm:priority(), Status :: status()}. --type session_info() :: {USR :: binary(), - Conn :: binary(), - IPS :: binary(), - Port :: inet:port_number(), +-type session_info() :: {USR :: jid:jid(), + Conn :: atom(), + Address :: {inet:ip_address(), inet:port_number()} | undefined, Prio :: ejabberd_sm:priority(), - NodeS :: binary(), + NodeS :: node(), Uptime :: integer()}. --type res_number_result() :: {ok | wrong_res_number, binary()}. +-type res_number_result() :: {ok | wrong_res_number | user_not_found, binary()}. --type kick_session_result() :: {ok | no_session, binary()}. +-type kick_user_result() :: #{binary() => term()}. --type set_presence_result() :: {ok | empty_resource, binary()}. +-type set_presence_result() :: {ok | empty_resource | user_not_found, binary()}. -export_type([res_number_result/0, - kick_session_result/0, set_presence_result/0, + kick_user_result/0, status_user_info/0, session_info/0, status/0]). --spec list_sessions() -> [session_info()]. +-spec list_sessions() -> {ok, [session_info()]}. list_sessions() -> USRIs = ejabberd_sm:get_full_session_list(), - lists:map(fun format_user_info/1, USRIs). + {ok, lists:map(fun format_user_info/1, USRIs)}. --spec list_sessions(jid:server()) -> [session_info()]. +-spec list_sessions(jid:server()) -> {ok, [session_info()]} | {domain_not_found, binary()}. list_sessions(Host) -> - USRIs = ejabberd_sm:get_vh_session_list(Host), - lists:map(fun format_user_info/1, USRIs). + case check_domain(Host) of + ok -> + USRIs = ejabberd_sm:get_vh_session_list(Host), + {ok, lists:map(fun format_user_info/1, USRIs)}; + Error -> + Error + end. --spec count_sessions() -> non_neg_integer(). +-spec count_sessions() -> {ok, non_neg_integer()}. count_sessions() -> - ejabberd_sm:get_total_sessions_number(). + {ok, ejabberd_sm:get_total_sessions_number()}. --spec count_sessions(jid:server()) -> non_neg_integer(). +-spec count_sessions(jid:server()) -> {ok, non_neg_integer()} | {domain_not_found, binary()}. count_sessions(Host) -> - ejabberd_sm:get_vh_session_number(Host). + case check_domain(Host) of + ok -> + {ok, ejabberd_sm:get_vh_session_number(Host)}; + Error -> + Error + end. --spec list_resources(jid:server()) -> [jid:literal_jid()]. +-spec list_resources(jid:server()) -> {ok, [jid:literal_jid()]} | {domain_not_found, binary()}. list_resources(Host) -> - Lst = ejabberd_sm:get_vh_session_list(Host), - [jid:to_binary(USR) || #session{usr = USR} <- Lst]. + case check_domain(Host) of + ok -> + Lst = ejabberd_sm:get_vh_session_list(Host), + {ok, [jid:to_binary(USR) || #session{usr = USR} <- Lst]}; + Error -> + Error + end. --spec list_user_resources(jid:jid()) -> [jid:literal_jid()]. +-spec list_user_resources(jid:jid()) -> {ok, [jid:literal_jid()]} | {user_not_found, binary()}. list_user_resources(JID) -> - ejabberd_sm:get_user_resources(JID). - --spec list_user_sessions(jid:user(), jid:server()) -> [session_info()]. -list_user_sessions(User, Host) -> - JID = jid:make(User, Host, <<>>), - list_user_sessions(JID). + case check_user(JID) of + ok -> + {ok, ejabberd_sm:get_user_resources(JID)}; + Error -> + Error + end. --spec list_user_sessions(jid:jid()) -> [session_info()]. +-spec list_user_sessions(jid:jid()) -> {ok, [session_info()]} | {user_not_found, binary()}. list_user_sessions(JID) -> - Resources = ejabberd_sm:get_user_resources(JID), - lists:foldl(fun(Res, Acc) -> - RJID = jid:replace_resource(JID, Res), - case ejabberd_sm:get_session(RJID) of - offline -> Acc; - Session -> [format_user_info(Session) | Acc] - end - end, [], Resources). - --spec num_resources(jid:user(), jid:server()) -> non_neg_integer(). -num_resources(User, Host) -> - JID = jid:make(User, Host, <<>>), - num_resources(JID). - --spec num_resources(jid:jid()) -> non_neg_integer(). -num_resources(JID) -> - length(ejabberd_sm:get_user_resources(JID)). + case check_user(JID) of + ok -> + Resources = ejabberd_sm:get_user_resources(JID), + {ok, lists:foldl( + fun(Res, Acc) -> + RJID = jid:replace_resource(JID, Res), + case ejabberd_sm:get_session(RJID) of + offline -> Acc; + Session -> [format_user_info(Session) | Acc] + end + end, + [], + Resources)}; + Error -> + Error + end. --spec get_user_resource(jid:user(), jid:server(), integer()) -> res_number_result(). -get_user_resource(User, Host, Num) -> - JID = jid:make(User, Host, <<>>), - get_user_resource(JID, Num). +-spec num_resources(jid:jid()) -> {ok, non_neg_integer()} | {user_not_found, binary()}. +num_resources(JID) -> + case check_user(JID) of + ok -> + {ok, length(ejabberd_sm:get_user_resources(JID))}; + Error -> + Error + end. -spec get_user_resource(jid:jid(), integer()) -> res_number_result(). get_user_resource(JID, Num) -> - Resources = ejabberd_sm:get_user_resources(JID), - case (0 < Num) and (Num =< length(Resources)) of - true -> - {ok, lists:nth(Num, Resources)}; - false -> - {wrong_res_number, iolist_to_binary(io_lib:format("Wrong resource number: ~p", [Num]))} + case check_user(JID) of + ok -> + Resources = ejabberd_sm:get_user_resources(JID), + case (0 < Num) and (Num =< length(Resources)) of + true -> + {ok, lists:nth(Num, Resources)}; + false -> + {wrong_res_number, + iolist_to_binary(io_lib:format("Wrong resource number: ~p", [Num]))} + end; + Error -> + Error end. --spec num_status_users(jid:server(), status()) -> non_neg_integer(). +-spec num_status_users(jid:server(), status()) -> {ok, non_neg_integer()} + | {domain_not_found, binary()}. num_status_users(Host, Status) -> - length(list_status_users(Host, Status)). + case check_domain(Host) of + ok -> + {ok, Sessions} = list_status_users(Host, Status), + {ok, length(Sessions)}; + Error -> + Error + end. --spec num_status_users(status()) -> non_neg_integer(). +-spec num_status_users(status()) -> {ok, non_neg_integer()}. num_status_users(Status) -> - length(list_status_users(Status)). + {ok, Sessions} = list_status_users(Status), + {ok, length(Sessions)}. --spec list_status_users(jid:server(), status()) -> [status_user_info()]. +-spec list_status_users(jid:server(), status()) -> {ok, [status_user_info()]} + | {domain_not_found, binary()}. list_status_users(Host, Status) -> - Sessions = ejabberd_sm:get_vh_session_list(Host), - get_status_list(Sessions, Status). + case check_domain(Host) of + ok -> + Sessions = ejabberd_sm:get_vh_session_list(Host), + {ok, get_status_list(Sessions, Status)}; + Error -> + Error + end. --spec list_status_users(status()) -> [status_user_info()]. +-spec list_status_users(status()) -> {ok, [status_user_info()]}. list_status_users(Status) -> Sessions = ejabberd_sm:get_full_session_list(), - get_status_list(Sessions, Status). - --spec set_presence(jid:user(), jid:server(), jid:resource(), - Type :: binary(), Show :: binary(), Status :: binary(), - Prio :: binary()) -> set_presence_result(). -set_presence(User, Host, Resource, Type, Show, Status, Priority) -> - JID = jid:make(User, Host, Resource), - set_presence(JID, Type, Show, Status, Priority). + {ok, get_status_list(Sessions, Status)}. -spec set_presence(jid:jid(), Type :: binary(), Show :: binary(), Status :: binary(), Prio :: binary()) -> set_presence_result(). set_presence(#jid{lresource = <<>>}, _Type, _Show, _Status, _Priority) -> {empty_resource, <<"The resource is empty. You need to provide a full JID">>}; set_presence(JID, Type, Show, Status, Priority) -> - Pid = ejabberd_sm:get_session_pid(JID), - USR = jid:to_binary(JID), - US = jid:to_binary(jid:to_bare(JID)), - - Children = maybe_pres_status(Status, - maybe_pres_priority(Priority, - maybe_pres_show(Show, []))), - Message = {xmlstreamelement, - #xmlel{name = <<"presence">>, - attrs = [{<<"from">>, USR}, {<<"to">>, US} | maybe_type_attr(Type)], - children = Children}}, - ok = p1_fsm_old:send_event(Pid, Message), - {ok, <<"Presence set successfully">>}. - --spec kick_sessions(jid:jid(), binary()) -> [kick_session_result()]. + case check_user(JID) of + ok -> + Pid = ejabberd_sm:get_session_pid(JID), + USR = jid:to_binary(JID), + US = jid:to_binary(jid:to_bare(JID)), + + Children = maybe_pres_status(Status, + maybe_pres_priority(Priority, + maybe_pres_show(Show, []))), + Message = {xmlstreamelement, + #xmlel{name = <<"presence">>, + attrs = [{<<"from">>, USR}, {<<"to">>, US} | maybe_type_attr(Type)], + children = Children}}, + ok = p1_fsm_old:send_event(Pid, Message), + {ok, <<"Presence set successfully">>}; + Error -> + Error + end. + +-spec kick_sessions(jid:jid(), binary()) -> {ok, [kick_user_result()]} | {user_not_found, binary()}. kick_sessions(JID, Reason) -> - lists:map( - fun(Resource) -> - service_admin_extra_sessions:kick_session( - jid:replace_resource(JID, Resource), Reason) - end, - ejabberd_sm:get_user_resources(JID)). - --spec kick_session(jid:user(), jid:server(), jid:resource(), binary()) -> kick_session_result(). -kick_session(User, Server, Resource, ReasonText) -> - kick_session(jid:make(User, Server, Resource), prepare_reason(ReasonText)). - --spec kick_session(jid:jid(), binary()) -> kick_session_result(). -kick_session(JID, ReasonText) -> - case ejabberd_c2s:terminate_session(JID, prepare_reason(ReasonText)) of + case check_user(JID) of + ok -> + {ok, lists:map( + fun(Resource) -> + FullJID = jid:replace_resource(JID, Resource), + case kick_session_internal(FullJID, Reason) of + {ok, Result} -> + {ok, Result}; + {Code, Message} -> + {ok, #{<<"jid">> => FullJID, + <<"kicked">> => false, + <<"code">> => atom_to_binary(Code), + <<"message">> => Message}} + end + end, + ejabberd_sm:get_user_resources(JID))}; + Error -> + Error + end. + +-spec kick_session(jid:jid(), binary() | null) -> {ok, kick_user_result()} + | {no_session | user_not_found, binary()}. +kick_session(JID, Reason) -> + case check_user(JID) of + ok -> + kick_session_internal(JID, Reason); + Error -> + Error + end. + +-spec kick_session_internal(jid:jid(), binary() | null) -> {ok, kick_user_result()} + | {no_session, binary()}. +kick_session_internal(JID, Reason) -> + case ejabberd_c2s:terminate_session(JID, prepare_reason(Reason)) of no_session -> {no_session, <<"No active session">>}; - {exit, ReasonText} -> - {ok, <<"Session kicked">>} + {exit, _Reason} -> + {ok, #{<<"jid">> => JID, + <<"kicked">> => true, + <<"message">> => <<"Session kicked">>}} end. --spec prepare_reason(binary() | string()) -> binary(). -prepare_reason(<<>>) -> +-spec prepare_reason(binary() | null) -> binary(). +prepare_reason(Reason) when Reason == <<>>; Reason == null -> <<"Kicked by administrator">>; -prepare_reason([Reason]) -> - prepare_reason(Reason); -prepare_reason(Reason) when is_list(Reason) -> - list_to_binary(Reason); prepare_reason(Reason) when is_binary(Reason) -> Reason. @@ -209,24 +255,21 @@ prepare_reason(Reason) when is_binary(Reason) -> -spec get_status_list([session()], status()) -> [status_user_info()]. get_status_list(Sessions0, StatusRequired) -> - Sessions = [ {catch ejabberd_c2s:get_presence(Pid), S, P} - || #session{sid = {_, Pid}, usr = {_, S, _}, priority = P} <- Sessions0 - ], + Sessions = [{catch ejabberd_c2s:get_presence(Pid), S, P} + || #session{sid = {_, Pid}, usr = {_, S, _}, priority = P} <- Sessions0], - [{User, Server, Resource, Priority, StatusText} + [{jid:make_noprep(User, Server, Resource), Priority, StatusText} || {{User, Resource, Status, StatusText}, Server, Priority} <- Sessions, Status == StatusRequired]. -spec format_user_info(ejabberd_sm:session()) -> session_info(). format_user_info(#session{sid = {Microseconds, Pid}, usr = Usr, priority = Priority, info = Info}) -> - Conn = atom_to_binary(maps:get(conn, Info, undefined)), - {Ip, Port} = maps:get(ip, Info, undefined), - IPS = list_to_binary(inet_parse:ntoa(Ip)), - NodeS = atom_to_binary(node(Pid)), + Conn = maps:get(conn, Info, undefined), + Address = maps:get(ip, Info, undefined), + Node = node(Pid), Uptime = (erlang:system_time(microsecond) - Microseconds) div 1000000, - BinJID = jid:to_binary(Usr), - {BinJID, Conn, IPS, Port, Priority, NodeS, Uptime}. + {Usr, Conn, Address, Priority, Node, Uptime}. -spec maybe_type_attr(binary())-> list(). maybe_type_attr(<<"available">>) -> @@ -255,3 +298,22 @@ maybe_pres_status(<<>>, Children) -> maybe_pres_status(Status, Children) -> [#xmlel{name = <<"status">>, children = [#xmlcdata{content = Status}]} | Children]. + +-spec check_domain(jid:server()) -> ok | {domain_not_found, binary()}. +check_domain(Domain) -> + case mongoose_domain_api:get_domain_host_type(Domain) of + {ok, _} -> ok; + {error, not_found} -> {domain_not_found, <<"Domain not found">>} + end. + +-spec check_user(jid:jid()) -> ok | {user_not_found, binary()}. +check_user(JID = #jid{lserver = LServer}) -> + case mongoose_domain_api:get_domain_host_type(LServer) of + {ok, HostType} -> + case ejabberd_auth:does_user_exist(HostType, JID, stored) of + true -> ok; + false -> {user_not_found, <<"Given user does not exist">>} + end; + {error, not_found} -> + {user_not_found, <<"User's domain does not exist">>} + end.