1: -module(graphql_muc_SUITE).
    2: 
    3: -compile([export_all, nowarn_export_all]).
    4: 
    5: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
    6: -import(graphql_helper, [execute_user/3, execute_auth/2, get_ok_value/2, get_err_msg/1,
    7:                          user_to_bin/1, user_to_full_bin/1, user_to_jid/1]).
    8: 
    9: -include_lib("common_test/include/ct.hrl").
   10: -include_lib("escalus/include/escalus_xmlns.hrl").
   11: -include_lib("eunit/include/eunit.hrl").
   12: -include_lib("exml/include/exml.hrl").
   13: 
   14: suite() ->
   15:     require_rpc_nodes([mim]) ++ escalus:suite().
   16: 
   17: all() ->
   18:     [{group, user_muc},
   19:      {group, admin_muc}].
   20: 
   21: groups() ->
   22:     [{user_muc, [parallel], user_muc_handler()},
   23:      {admin_muc, [parallel], admin_muc_handler()}].
   24: 
   25: user_muc_handler() ->
   26:     [user_create_and_delete_room,
   27:      user_try_delete_nonexistent_room,
   28:      user_try_delete_room_by_not_owner,
   29:      user_try_create_instant_room_with_nonexistent_domain,
   30:      user_list_rooms,
   31:      user_list_room_users,
   32:      user_list_room_users_without_anonymous_mode,
   33:      user_try_list_room_users_without_permission,
   34:      user_try_list_nonexistent_room_users,
   35:      user_change_room_config,
   36:      user_try_change_nonexistent_room_config,
   37:      user_get_room_config,
   38:      user_try_get_nonexistent_room_config,
   39:      user_invite_user,
   40:      user_kick_user,
   41:      user_try_kick_user_from_nonexistent_room,
   42:      user_try_kick_user_without_moderator_resource,
   43:      user_send_message_to_room,
   44:      user_send_message_to_room_with_specified_res,
   45:      user_send_private_message,
   46:      user_without_session_send_message_to_room,
   47:      user_get_room_messages,
   48:      user_try_get_nonexistent_room_messages,
   49:      user_try_get_room_messages_without_permission,
   50:      user_owner_set_user_affiliation,
   51:      user_admin_set_user_affiliation,
   52:      user_member_set_user_affiliation,
   53:      user_try_set_nonexistent_room_affiliation,
   54:      user_moderator_set_user_role,
   55:      user_participant_set_user_role,
   56:      user_try_set_nonexistent_room_role,
   57:      user_can_enter_room,
   58:      user_can_enter_room_with_password,
   59:      user_can_exit_room,
   60:      user_list_room_affiliations,
   61:      user_try_list_room_affiliations_without_permission,
   62:      user_try_list_nonexistent_room_affiliations
   63:     ].
   64: 
   65: admin_muc_handler() ->
   66:     [admin_create_and_delete_room,
   67:      admin_try_create_instant_room_with_nonexistent_domain,
   68:      admin_try_create_instant_room_with_nonexistent_user,
   69:      admin_try_delete_nonexistent_room,
   70:      admin_try_delete_room_with_nonexistent_domain,
   71:      admin_list_rooms,
   72:      admin_list_room_users,
   73:      admin_try_list_users_from_nonexistent_room,
   74:      admin_change_room_config,
   75:      admin_try_change_nonexistent_room_config,
   76:      admin_get_room_config,
   77:      admin_try_get_nonexistent_room_config,
   78:      admin_invite_user,
   79:      admin_invite_user_with_password,
   80:      admin_try_invite_user_to_nonexistent_room,
   81:      admin_kick_user,
   82:      admin_try_kick_user_from_nonexistent_room,
   83:      admin_try_kick_user_from_room_without_moderators,
   84:      admin_send_message_to_room,
   85:      admin_send_private_message,
   86:      admin_get_room_messages,
   87:      admin_try_get_nonexistent_room_messages,
   88:      admin_set_user_affiliation,
   89:      admin_try_set_nonexistent_room_user_affiliation,
   90:      admin_set_user_role,
   91:      admin_try_set_nonexistent_room_user_role,
   92:      admin_try_set_nonexistent_nick_role,
   93:      admin_try_set_user_role_in_room_without_moderators,
   94:      admin_make_user_enter_room,
   95:      admin_make_user_enter_room_with_password,
   96:      admin_make_user_enter_room_bare_jid,
   97:      admin_make_user_exit_room,
   98:      admin_make_user_exit_room_bare_jid,
   99:      admin_list_room_affiliations,
  100:      admin_try_list_nonexistent_room_affiliations
  101:     ].
  102: 
  103: init_per_suite(Config) ->
  104:     HostType = domain_helper:host_type(),
  105:     Config2 = escalus:init_per_suite(Config),
  106:     Config3 = dynamic_modules:save_modules(HostType, Config2),
  107:     Config4 = rest_helper:maybe_enable_mam(mam_helper:backend(), HostType, Config3),
  108:     dynamic_modules:restart(HostType, mod_disco,
  109:                             config_parser_helper:default_mod_config(mod_disco)),
  110:     muc_helper:load_muc(),
  111:     mongoose_helper:ensure_muc_clean(),
  112:     Config4.
  113: 
  114: end_per_suite(Config) ->
  115:     escalus_fresh:clean(),
  116:     mongoose_helper:ensure_muc_clean(),
  117:     muc_helper:unload_muc(),
  118:     dynamic_modules:restore_modules(Config),
  119:     escalus:end_per_suite(Config).
  120: 
  121: init_per_group(admin_muc, Config) ->
  122:     graphql_helper:init_admin_handler(Config);
  123: init_per_group(user_muc, Config) ->
  124:     [{schema_endpoint, user} | Config].
  125: 
  126: end_per_group(_GN, Config) ->
  127:     Config.
  128: 
  129: init_per_testcase(TC, Config) ->
  130:     rest_helper:maybe_skip_mam_test_cases(TC, [user_get_room_messages,
  131:                                                admin_get_room_messages], Config).
  132: 
  133: end_per_testcase(TC, Config) ->
  134:     escalus:end_per_testcase(TC, Config).
  135: 
  136: -define(CREATE_INSTANT_ROOM_PATH, [data, muc, createInstantRoom]).
  137: -define(LIST_ROOMS_PATH, [data, muc, listRooms]).
  138: -define(INVITE_USER_PATH, [data, muc, inviteUser]).
  139: -define(KICK_USER_PATH, [data, muc, kickUser]).
  140: -define(DELETE_ROOM_PATH, [data, muc, deleteRoom]).
  141: -define(SEND_MESSAGE_PATH, [data, muc, sendMessageToRoom]).
  142: -define(SEND_PRIV_MESG_PATH, [data, muc, sendPrivateMessage]).
  143: -define(GET_MESSAGES_PATH, [data, muc, getRoomMessages]).
  144: -define(LIST_ROOM_USERS_PATH, [data, muc, listRoomUsers]).
  145: -define(LIST_ROOM_AFFILIATIONS_PATH, [data, muc, listRoomAffiliations]).
  146: -define(CHANGE_ROOM_CONFIG_PATH, [data, muc, changeRoomConfiguration]).
  147: -define(GET_ROOM_CONFIG_PATH, [data, muc, getRoomConfig]).
  148: -define(SET_AFFILIATION_PATH, [data, muc, setUserAffiliation]).
  149: -define(SET_ROLE_PATH, [data, muc, setUserRole]).
  150: -define(ENTER_ROOM_PATH, [data, muc, enterRoom]).
  151: -define(EXIT_ROOM_PATH, [data, muc, exitRoom]).
  152: 
  153: -define(NONEXISTENT_ROOM, <<"room@room">>).
  154: -define(NONEXISTENT_ROOM2, <<"room@", (muc_helper:muc_host())/binary>>).
  155: -define(PASSWORD, <<"pa5sw0rd">>).
  156: 
  157: admin_list_rooms(Config) ->
  158:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun admin_list_rooms_story/3).
  159: 
  160: admin_list_rooms_story(Config, Alice, Bob) ->
  161:     AliceJID = jid:from_binary(escalus_client:short_jid(Alice)),
  162:     BobJID = jid:from_binary(escalus_client:short_jid(Bob)),
  163:     AliceRoom = rand_name(),
  164:     BobRoom = rand_name(),
  165:     muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []),
  166:     muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, [{public_list, false}]),
  167:     Res = execute_auth(admin_list_rooms_body(muc_helper:muc_host(), Alice, null, null), Config),
  168:     #{<<"rooms">> := Rooms } = get_ok_value(?LIST_ROOMS_PATH, Res),
  169:     ?assert(contain_room(AliceRoom, Rooms)),
  170:     ?assert(contain_room(BobRoom, Rooms)).
  171: 
  172: admin_create_and_delete_room(Config) ->
  173:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_create_and_delete_room_story/2).
  174: 
  175: admin_create_and_delete_room_story(Config, Alice) ->
  176:     Name = <<"first-alice-room">>,
  177:     MUCServer = muc_helper:muc_host(),
  178:     RoomJID = jid:make_bare(Name, MUCServer),
  179:     % Create instant room
  180:     Res = execute_auth(admin_create_instant_room_body(MUCServer, Name, Alice, <<"Ali">>), Config),
  181:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
  182:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)),
  183:     Res2 = execute_auth(admin_list_rooms_body(MUCServer, Alice, null, null), Config),
  184:     ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))),
  185:     % Delete room
  186:     Res3 = execute_auth(delete_room_body(RoomJID, null), Config),
  187:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3),
  188:                                           <<"successfully">>)),
  189:     Res4 = execute_auth(admin_list_rooms_body(MUCServer, Alice, null, null), Config),
  190:     ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))).
  191: 
  192: admin_try_create_instant_room_with_nonexistent_domain(Config) ->
  193:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  194:                                     fun admin_try_create_instant_room_with_nonexistent_domain_story/2).
  195: 
  196: admin_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) ->
  197:     Res = execute_auth(admin_create_instant_room_body(<<"unknown">>, rand_name(), Alice, <<"Ali">>),
  198:                        Config),
  199:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  200: 
  201: admin_try_create_instant_room_with_nonexistent_user(Config) ->
  202:     Name = rand_name(),
  203:     MUCServer = muc_helper:muc_host(),
  204:     JID = <<(rand_name())/binary, "@localhost">>,
  205:     Res = execute_auth(admin_create_instant_room_body(MUCServer, Name, JID, <<"Ali">>), Config),
  206:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  207: 
  208: admin_try_delete_nonexistent_room(Config) ->
  209:     RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()),
  210:     Res = execute_auth(delete_room_body(RoomJID, null), Config),
  211:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
  212: 
  213: admin_try_delete_room_with_nonexistent_domain(Config) ->
  214:     RoomJID = jid:make_bare(<<"unknown">>, <<"unknown">>),
  215:     Res = execute_auth(delete_room_body(RoomJID, null), Config),
  216:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
  217: 
  218: admin_invite_user(Config) ->
  219:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_invite_user_story/3).
  220: 
  221: admin_invite_user_story(Config, Alice, Bob) ->
  222:     RoomJIDBin = ?config(room_jid, Config),
  223:     RoomJID = jid:from_binary(RoomJIDBin),
  224:     Res = execute_auth(admin_invite_user_body(RoomJID, Alice, Bob, null), Config),
  225:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res),
  226:                                           <<"successfully">>)),
  227:     Stanza = escalus:wait_for_stanza(Bob),
  228:     escalus:assert(is_message, Stanza),
  229:     ?assertEqual(RoomJIDBin,
  230:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])),
  231:     ?assertEqual(undefined, exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"password">>}])).
  232: 
  233: admin_invite_user_with_password(Config) ->
  234:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
  235:                                [{alice, 1}, {bob, 1}], fun admin_invite_user_with_password/3).
  236: 
  237: admin_invite_user_with_password(Config, Alice, Bob) ->
  238:     RoomJIDBin = ?config(room_jid, Config),
  239:     RoomJID = jid:from_binary(RoomJIDBin),
  240:     Res = execute_auth(admin_invite_user_body(RoomJID, Alice, Bob, null), Config),
  241:     assert_success(?INVITE_USER_PATH, Res),
  242:     Stanza = escalus:wait_for_stanza(Bob),
  243:     escalus:assert(is_message, Stanza),
  244:     ?assertEqual(RoomJIDBin,
  245:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])),
  246:     ?assertEqual(?PASSWORD, exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"password">>}])).
  247: 
  248: admin_try_invite_user_to_nonexistent_room(Config) ->
  249:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  250:                                     fun admin_try_invite_user_to_nonexistent_room_story/3).
  251: 
  252: admin_try_invite_user_to_nonexistent_room_story(Config, Alice, Bob) ->
  253:     Res = execute_auth(admin_invite_user_body(?NONEXISTENT_ROOM, Alice, Bob, null), Config),
  254:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  255: 
  256: admin_kick_user(Config) ->
  257:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_kick_user_story/3).
  258: 
  259: admin_kick_user_story(Config, Alice, Bob) ->
  260:     RoomJIDBin = ?config(room_jid, Config),
  261:     RoomJID = jid:from_binary(RoomJIDBin),
  262:     BobNick = <<"Bobek">>,
  263:     Reason = <<"You are too laud">>,
  264:     enter_room(RoomJID, Alice, <<"ali">>),
  265:     enter_room(RoomJID, Bob, BobNick),
  266:     Res = execute_auth(kick_user_body(RoomJID, BobNick, Reason), Config),
  267:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res),
  268:                                           <<"successfully">>)),
  269:     escalus:wait_for_stanzas(Bob, 2),
  270:     KickStanza = escalus:wait_for_stanza(Bob),
  271:     escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza),
  272:     ?assertEqual(Reason,
  273:                  exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>},
  274:                                               {element, <<"reason">>}, cdata])).
  275: 
  276: admin_try_kick_user_from_room_without_moderators(Config) ->
  277:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  278:                                fun admin_try_kick_user_from_room_without_moderators/3).
  279: 
  280: admin_try_kick_user_from_room_without_moderators(Config, _Alice, Bob) ->
  281:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  282:     BobNick = <<"Bobek">>,
  283:     enter_room(RoomJID, Bob, BobNick),
  284:     Res = execute_auth(kick_user_body(RoomJID, BobNick, null), Config),
  285:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  286: 
  287: admin_try_kick_user_from_nonexistent_room(Config) ->
  288:     Res = execute_auth(kick_user_body(?NONEXISTENT_ROOM, <<"ali">>, null), Config),
  289:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  290: 
  291: admin_send_message_to_room(Config) ->
  292:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  293:                                fun admin_send_message_to_room_story/3).
  294: 
  295: admin_send_message_to_room_story(Config, _Alice, Bob) ->
  296:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  297:     Message = <<"Hello All!">>,
  298:     BobNick = <<"Bobek">>,
  299:     enter_room(RoomJID, Bob, BobNick),
  300:     escalus:wait_for_stanza(Bob),
  301:     % Try send messsage from bare JID,
  302:     BareBob = escalus_client:short_jid(Bob),
  303:     Res = execute_auth(admin_send_message_to_room_body(RoomJID, BareBob, Message), Config),
  304:     assert_no_full_jid(Res),
  305:     % Send message
  306:     Res1 = execute_auth(admin_send_message_to_room_body(RoomJID, Bob, Message), Config),
  307:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res1),
  308:                                           <<"successfully">>)),
  309:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
  310:                               escalus:wait_for_stanza(Bob)).
  311: 
  312: admin_send_private_message(Config) ->
  313:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  314:                                fun admin_send_private_message/3).
  315: 
  316: admin_send_private_message(Config, Alice, Bob) ->
  317:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  318:     Message = <<"Hello Bob!">>,
  319:     BobNick = <<"Bobek">>,
  320:     AliceNick = <<"Ali">>,
  321:     enter_room(RoomJID, Alice, AliceNick),
  322:     enter_room(RoomJID, Bob, BobNick),
  323:     escalus:wait_for_stanzas(Bob, 2),
  324:     % Try send private messsage from bare JID,
  325:     BareAlice = escalus_client:short_jid(Alice),
  326:     Res = execute_auth(admin_send_private_message_body(RoomJID, BareAlice, BobNick, Message),
  327:                        Config),
  328:     assert_no_full_jid(Res),
  329:     % Send message
  330:     Res1 = execute_auth(admin_send_private_message_body(RoomJID, Alice, BobNick, Message), Config),
  331:     assert_success(?SEND_PRIV_MESG_PATH, Res1),
  332:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
  333:                               escalus:wait_for_stanza(Bob)).
  334: 
  335: admin_get_room_config(Config) ->
  336:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_get_room_config_story/2).
  337: 
  338: admin_get_room_config_story(Config, _Alice) ->
  339:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  340:     Res = execute_auth(get_room_config_body(RoomJID), Config),
  341:     assert_default_room_config(Res).
  342: 
  343: admin_try_get_nonexistent_room_config(Config) ->
  344:     Res = execute_auth(get_room_config_body(?NONEXISTENT_ROOM), Config),
  345:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  346: 
  347: admin_change_room_config(Config) ->
  348:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_change_room_config_story/2).
  349: 
  350: admin_change_room_config_story(Config, _Alice) ->
  351:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  352:     Title = <<"aloes">>,
  353:     Description = <<"The chat about aloes">>,
  354:     Public = false,
  355:     RoomConfig = #{title => Title, description => Description, public => Public},
  356:     Res = execute_auth(change_room_config_body(RoomJID, RoomConfig), Config),
  357:     ?assertMatch(#{<<"title">> := Title,
  358:                    <<"description">> := Description,
  359:                    <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)).
  360: 
  361: admin_try_change_nonexistent_room_config(Config) ->
  362:     RoomConfig = #{title => <<"NewTitle">>},
  363:     Res = execute_auth(change_room_config_body(?NONEXISTENT_ROOM, RoomConfig), Config),
  364:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  365: 
  366: admin_list_room_users(Config) ->
  367:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  368:                                fun admin_list_room_users_story/3).
  369: 
  370: admin_list_room_users_story(Config, Alice, Bob) ->
  371:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  372:     BobNick = <<"Bobek">>,
  373:     AliceNick = <<"Ali">>,
  374:     enter_room(RoomJID, Bob, BobNick),
  375:     enter_room(RoomJID, Alice, AliceNick),
  376:     Res = execute_auth(list_room_users_body(RoomJID), Config),
  377:     ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>},
  378:                      {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}],
  379:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
  380: 
  381: admin_try_list_users_from_nonexistent_room(Config) ->
  382:     Res = execute_auth(list_room_users_body(?NONEXISTENT_ROOM), Config),
  383:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  384: 
  385: admin_get_room_messages(Config) ->
  386:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  387:                                fun admin_get_room_messages_story/3).
  388: 
  389: admin_get_room_messages_story(Config, Alice, Bob) ->
  390:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  391:     enter_room(RoomJID, Bob, <<"Bobek">>),
  392:     enter_room(RoomJID, Alice, <<"Ali">>),
  393:     escalus:wait_for_stanzas(Bob, 2),
  394:     execute_auth(admin_send_message_to_room_body(RoomJID, Bob, <<"Hi!">>), Config),
  395:     escalus:wait_for_stanzas(Bob, 1),
  396:     mam_helper:maybe_wait_for_archive(Config),
  397:     Res = execute_auth(get_room_messages_body(RoomJID, 50, null), Config),
  398:     #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} =
  399:         get_ok_value(?GET_MESSAGES_PATH, Res),
  400:     ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)).
  401: 
  402: admin_try_get_nonexistent_room_messages(Config) ->
  403:     Res = execute_auth(get_room_messages_body(?NONEXISTENT_ROOM, null, null), Config),
  404:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  405: 
  406: 
  407: admin_set_user_affiliation(Config) ->
  408:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  409:                                fun admin_set_user_affiliation/3).
  410: 
  411: admin_set_user_affiliation(Config, _Alice, Bob) ->
  412:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  413:     % Grant member affiliation
  414:     Res = execute_auth(set_user_affiliation_body(RoomJID, Bob, member), Config),
  415:     assert_success(?SET_AFFILIATION_PATH, Res),
  416:     assert_user_affiliation(RoomJID, Bob, member),
  417:     % Grant admin affiliation
  418:     Res1 = execute_auth(set_user_affiliation_body(RoomJID, Bob, admin), Config),
  419:     assert_success(?SET_AFFILIATION_PATH, Res1),
  420:     assert_user_affiliation(RoomJID, Bob, admin),
  421:     % Grant owner affiliation
  422:     Res2 = execute_auth(set_user_affiliation_body(RoomJID, Bob, owner), Config),
  423:     assert_success(?SET_AFFILIATION_PATH, Res2),
  424:     assert_user_affiliation(RoomJID, Bob, owner),
  425:     % Revoke affiliation
  426:     Res3 = execute_auth(set_user_affiliation_body(RoomJID, Bob, none), Config),
  427:     assert_success(?SET_AFFILIATION_PATH, Res3),
  428:     assert_user_affiliation(RoomJID, Bob, none),
  429:     % Ban user
  430:     Res4 = execute_auth(set_user_affiliation_body(RoomJID, Bob, outcast), Config),
  431:     assert_success(?SET_AFFILIATION_PATH, Res4),
  432:     assert_user_affiliation(RoomJID, Bob, outcast).
  433: 
  434: admin_try_set_nonexistent_room_user_affiliation(Config) ->
  435:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  436:                                     fun admin_try_set_nonexistent_room_user_affiliation/2).
  437: 
  438: admin_try_set_nonexistent_room_user_affiliation(Config, Alice) ->
  439:     Res = execute_auth(set_user_affiliation_body(?NONEXISTENT_ROOM, Alice, admin), Config),
  440:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  441: 
  442: admin_set_user_role(Config) ->
  443:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_set_user_role/3).
  444: 
  445: admin_set_user_role(Config, Alice, Bob) ->
  446:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  447:     BobNick = <<"Boobek">>,
  448:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
  449:     enter_room(RoomJID, Bob, BobNick),
  450:     % Change from participant to visitor
  451:     Res = execute_auth(set_user_role_body(RoomJID, BobNick, visitor), Config),
  452:     assert_success(?SET_ROLE_PATH, Res),
  453:     assert_user_role(RoomJID, Bob, visitor),
  454:     % Change from visitor to participant
  455:     Res1 = execute_auth(set_user_role_body(RoomJID, BobNick, participant), Config),
  456:     assert_success(?SET_ROLE_PATH, Res1),
  457:     assert_user_role(RoomJID, Bob, participant),
  458:     % Change from participant to moderator
  459:     Res2 = execute_auth(set_user_role_body(RoomJID, BobNick, moderator), Config),
  460:     assert_success(?SET_ROLE_PATH, Res2),
  461:     assert_user_role(RoomJID, Bob, moderator).
  462: 
  463: admin_try_set_nonexistent_nick_role(Config) ->
  464:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_try_set_nonexistent_nick_role/2).
  465: 
  466: admin_try_set_nonexistent_nick_role(Config, Alice) ->
  467:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  468:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
  469:     Res = execute_auth(set_user_role_body(RoomJID, <<"kik">>, visitor), Config),
  470:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)).
  471: 
  472: admin_try_set_user_role_in_room_without_moderators(Config) ->
  473:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  474:                                fun admin_try_set_user_role_in_room_without_moderators/3).
  475: 
  476: admin_try_set_user_role_in_room_without_moderators(Config, _Alice, Bob) ->
  477:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  478:     BobNick = <<"Boobek">>,
  479:     enter_room(RoomJID, Bob, BobNick),
  480:     Res = execute_auth(set_user_role_body(RoomJID, BobNick, visitor), Config),
  481:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  482: 
  483: admin_try_set_nonexistent_room_user_role(Config) ->
  484:     Res = execute_auth(set_user_role_body(?NONEXISTENT_ROOM, <<"Alice">>, moderator), Config),
  485:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  486: 
  487: admin_make_user_enter_room(Config) ->
  488:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_enter_room/2).
  489: 
  490: admin_make_user_enter_room(Config, Alice) ->
  491:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  492:     Nick = <<"ali">>,
  493:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
  494:     % Alice enter room with password
  495:     Res = execute_auth(admin_enter_room_body(RoomJID, Alice, Nick, null), Config),
  496:     assert_success(?ENTER_ROOM_PATH, Res),
  497:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)).
  498: 
  499: admin_make_user_enter_room_with_password(Config) ->
  500:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
  501:                                [{alice, 1}, {bob, 1}],
  502:                                fun admin_make_user_enter_room_with_password/3).
  503: 
  504: admin_make_user_enter_room_with_password(Config, Alice, Bob) ->
  505:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  506:     Nick = <<"ali">>,
  507:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
  508:     % Alice enter room with password
  509:     Res = execute_auth(admin_enter_room_body(RoomJID, Alice, Nick, ?PASSWORD), Config),
  510:     assert_success(?ENTER_ROOM_PATH, Res),
  511:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)),
  512:     % Bob try enter room without password 
  513:     Res1 = execute_auth(admin_enter_room_body(RoomJID, Bob, <<"Bobek">>, null), Config),
  514:     assert_success(?ENTER_ROOM_PATH, Res1),
  515:     ?assertMatch([_], get_room_users(RoomJID)),
  516:     % Bob enter room with password
  517:     Res2 = execute_auth(admin_enter_room_body(RoomJID, Bob, <<"Bobek">>, ?PASSWORD), Config),
  518:     assert_success(?ENTER_ROOM_PATH, Res2),
  519:     ?assertMatch([_, _], get_room_users(RoomJID)).
  520: 
  521: admin_make_user_enter_room_bare_jid(Config) ->
  522:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_enter_room_bare_jid/2).
  523: 
  524: admin_make_user_enter_room_bare_jid(Config, Alice) ->
  525:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  526:     BareAlice = escalus_client:short_jid(Alice),
  527:     Res = execute_auth(admin_enter_room_body(RoomJID, BareAlice, <<"Ali">>, null), Config),
  528:     assert_no_full_jid(Res).
  529: 
  530: admin_make_user_exit_room(Config) ->
  531:     muc_helper:story_with_room(Config, [{persistent, true}], [{alice, 1}],
  532:                                fun admin_make_user_exit_room/2).
  533: 
  534: admin_make_user_exit_room(Config, Alice) ->
  535:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  536:     Nick = <<"ali">>,
  537:     enter_room(RoomJID, Alice, Nick),
  538:     ?assertMatch([_], get_room_users(RoomJID)),
  539:     Res = execute_auth(admin_exit_room_body(RoomJID, Alice, Nick), Config),
  540:     assert_success(?EXIT_ROOM_PATH, Res),
  541:     ?assertMatch([], get_room_users(RoomJID)).
  542: 
  543: admin_make_user_exit_room_bare_jid(Config) ->
  544:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_exit_room_bare_jid/2).
  545: 
  546: admin_make_user_exit_room_bare_jid(Config, Alice) ->
  547:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  548:     BareAlice = escalus_client:short_jid(Alice),
  549:     Nick = <<"ali">>,
  550:     enter_room(RoomJID, Alice, Nick),
  551:     Res = execute_auth(admin_exit_room_body(RoomJID, BareAlice, Nick), Config),
  552:     assert_no_full_jid(Res).
  553: 
  554: admin_list_room_affiliations(Config) ->
  555:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  556:                                fun admin_list_room_affiliations/3).
  557: 
  558: admin_list_room_affiliations(Config, Alice, Bob) ->
  559:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  560:     BobNick = <<"Bobek">>,
  561:     AliceNick = <<"Ali">>,
  562:     enter_room(RoomJID, Bob, BobNick),
  563:     enter_room(RoomJID, Alice, AliceNick),
  564:     AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  565:     BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  566:     % List all owners
  567:     Res = execute_auth(list_room_affiliations_body(RoomJID, owner), Config),
  568:     ?assertMatch([#{<<"jid">> := AliceJID, <<"affiliation">> := <<"OWNER">>}],
  569:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res)),
  570:     % List all members
  571:     execute_auth(set_user_affiliation_body(RoomJID, Bob, member), Config),
  572:     Res1 = execute_auth(list_room_affiliations_body(RoomJID, member), Config),
  573:     ?assertMatch([#{<<"jid">> := BobJID, <<"affiliation">> := <<"MEMBER">>}],
  574:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res1)),
  575:     % List all
  576:     Res2 = execute_auth(list_room_affiliations_body(RoomJID, null), Config),
  577:     ?assertMatch([_, _], get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res2)).
  578: 
  579: admin_try_list_nonexistent_room_affiliations(Config) ->
  580:     Res = execute_auth(list_room_affiliations_body(?NONEXISTENT_ROOM, null), Config),
  581:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  582: 
  583: %% User test cases
  584: 
  585: user_list_rooms(Config) ->
  586:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun user_list_rooms_story/3).
  587: 
  588: user_list_rooms_story(Config, Alice, Bob) ->
  589:     AliceJID = jid:from_binary(escalus_client:short_jid(Alice)),
  590:     BobJID = jid:from_binary(escalus_client:short_jid(Bob)),
  591:     AliceRoom = rand_name(),
  592:     BobRoom = rand_name(),
  593:     muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []),
  594:     muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, []),
  595: 
  596:     Res = execute_user(user_list_rooms_body(muc_helper:muc_host(), null, null), Alice, Config),
  597:     #{<<"rooms">> := Rooms } = get_ok_value(?LIST_ROOMS_PATH, Res),
  598:     ?assert(contain_room(AliceRoom, Rooms)),
  599:     ?assert(contain_room(BobRoom, Rooms)).
  600: 
  601: user_create_and_delete_room(Config) ->
  602:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_create_and_delete_room_story/2).
  603: 
  604: user_create_and_delete_room_story(Config, Alice) ->
  605:     Name = rand_name(),
  606:     MUCServer = muc_helper:muc_host(),
  607:     RoomJID = jid:make_bare(Name, MUCServer),
  608:     % Create instant room
  609:     Res = execute_user(user_create_instant_room_body(MUCServer, Name, <<"Ali">>), Alice, Config),
  610:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
  611:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)),
  612:     Res2 = execute_user(user_list_rooms_body(MUCServer, null, null), Alice, Config),
  613:     ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))),
  614:     % Delete room
  615:     Res3 = execute_user(delete_room_body(RoomJID, null), Alice, Config),
  616:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3),
  617:                                           <<"successfully">>)),
  618:     Res4 = execute_user(user_list_rooms_body(MUCServer, null, null), Alice, Config),
  619:     ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))).
  620: 
  621: user_try_create_instant_room_with_nonexistent_domain(Config) ->
  622:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  623:                                     fun user_try_create_instant_room_with_nonexistent_domain_story/2).
  624: 
  625: user_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) ->
  626:     Res = execute_user(user_create_instant_room_body(<<"unknown">>, rand_name(), <<"Ali">>),
  627:                        Alice, Config),
  628:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  629: 
  630: user_try_delete_nonexistent_room(Config) ->
  631:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  632:                                     fun user_try_delete_nonexistent_room_story/2).
  633: 
  634: user_try_delete_nonexistent_room_story(Config, Alice) ->
  635:     RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()),
  636:     Res = execute_user(delete_room_body(RoomJID, null), Alice, Config),
  637:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
  638: 
  639: user_try_delete_room_by_not_owner(Config) ->
  640:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  641:                                fun user_try_delete_room_by_not_owner_story/3).
  642: 
  643: user_try_delete_room_by_not_owner_story(Config, _Alice, Bob) ->
  644:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  645:     Res = execute_user(delete_room_body(RoomJID, null), Bob, Config),
  646:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
  647: 
  648: user_invite_user(Config) ->
  649:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_invite_user_story/3).
  650: 
  651: user_invite_user_story(Config, Alice, Bob) ->
  652:     RoomJIDBin = ?config(room_jid, Config),
  653:     RoomJID = jid:from_binary(RoomJIDBin),
  654:     Res = execute_user(user_invite_user_body(RoomJID, Bob, null), Alice, Config),
  655:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res),
  656:                                           <<"successfully">>)),
  657:     Stanza = escalus:wait_for_stanza(Bob),
  658:     escalus:assert(is_message, Stanza),
  659:     ?assertEqual(RoomJIDBin,
  660:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])).
  661: 
  662: user_kick_user(Config) ->
  663:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_kick_user_story/3).
  664: 
  665: user_kick_user_story(Config, Alice, Bob) ->
  666:     RoomJIDBin = ?config(room_jid, Config),
  667:     RoomJID = jid:from_binary(RoomJIDBin),
  668:     BobNick = <<"Bobek">>,
  669:     Reason = <<"You are too loud">>,
  670:     enter_room(RoomJID, Alice, <<"ali">>),
  671:     enter_room(RoomJID, Bob, BobNick),
  672:     Res = execute_user(kick_user_body(RoomJID, BobNick, Reason), Alice, Config),
  673:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res),
  674:                                           <<"successfully">>)),
  675:     escalus:wait_for_stanzas(Bob, 2),
  676:     KickStanza = escalus:wait_for_stanza(Bob),
  677:     escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza),
  678:     ?assertEqual(Reason,
  679:                  exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>},
  680:                                               {element, <<"reason">>}, cdata])).
  681: 
  682: user_try_kick_user_without_moderator_resource(Config) ->
  683:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  684:                                fun user_try_kick_user_without_moderator_resource/3).
  685: 
  686: user_try_kick_user_without_moderator_resource(Config, Alice, Bob) ->
  687:     RoomJIDBin = ?config(room_jid, Config),
  688:     RoomJID = jid:from_binary(RoomJIDBin),
  689:     BobNick = <<"Bobek">>,
  690:     enter_room(RoomJID, Bob, BobNick),
  691:     Res = execute_user(kick_user_body(RoomJID, BobNick, null), Alice, Config),
  692:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  693: 
  694: user_try_kick_user_from_nonexistent_room(Config) ->
  695:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  696:                                     fun user_try_kick_user_from_nonexistent_room/2).
  697: 
  698: user_try_kick_user_from_nonexistent_room(Config, Alice) ->
  699:     Res = execute_user(kick_user_body(?NONEXISTENT_ROOM, <<"bobi">>, null), Alice, Config),
  700:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  701: 
  702: user_send_message_to_room(Config) ->
  703:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  704:                                fun user_send_message_to_room_story/3).
  705: 
  706: user_send_message_to_room_story(Config, _Alice, Bob) ->
  707:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  708:     Message = <<"Hello All!">>,
  709:     BobNick = <<"Bobek">>,
  710:     enter_room(RoomJID, Bob, BobNick),
  711:     escalus:wait_for_stanza(Bob),
  712:     % Send message
  713:     Res = execute_user(user_send_message_to_room_body(RoomJID, Message, null), Bob, Config),
  714:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res),
  715:                                           <<"successfully">>)),
  716:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
  717:                               escalus:wait_for_stanza(Bob)).
  718: 
  719: user_send_message_to_room_with_specified_res(Config) ->
  720:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 2}],
  721:                                fun user_send_message_to_room_with_specified_res_story/4).
  722: 
  723: user_send_message_to_room_with_specified_res_story(Config, _Alice, Bob, Bob2) ->
  724:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  725:     Message = <<"Hello All!">>,
  726:     BobNick = <<"Bobek">>,
  727:     enter_room(RoomJID, Bob2, BobNick),
  728:     escalus:wait_for_stanza(Bob2),
  729:     % Send message
  730:     Res = execute_user(user_send_message_to_room_body(RoomJID, Message, <<"res2">>), Bob, Config),
  731:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res),
  732:                                           <<"successfully">>)),
  733:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
  734:                               escalus:wait_for_stanza(Bob2)).
  735: 
  736: user_send_private_message(Config) ->
  737:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  738:                                fun user_send_private_message/3).
  739: 
  740: user_send_private_message(Config, Alice, Bob) ->
  741:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  742:     Message = <<"Hello Bob!">>,
  743:     BobNick = <<"Bobek">>,
  744:     AliceNick = <<"Ali">>,
  745:     enter_room(RoomJID, Bob, BobNick),
  746:     enter_room(RoomJID, Alice, AliceNick),
  747:     escalus:wait_for_stanzas(Bob, 2),
  748:     % Send message
  749:     Res = execute_user(user_send_private_message_body(RoomJID, Message, BobNick, null),
  750:                        Alice, Config),
  751:     assert_success(?SEND_PRIV_MESG_PATH, Res),
  752:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
  753:                               escalus:wait_for_stanza(Bob)).
  754: 
  755: user_send_private_message_with_specified_res(Config) ->
  756:     muc_helper:story_with_room(Config, [], [{alice, 2}, {bob, 1}],
  757:                                fun user_send_private_message/3).
  758: 
  759: user_send_private_message_with_specified_res(Config, Alice, Alice2, Bob) ->
  760:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  761:     Message = <<"Hello Bob!">>,
  762:     BobNick = <<"Bobek">>,
  763:     AliceNick = <<"Ali">>,
  764:     enter_room(RoomJID, Bob, BobNick),
  765:     enter_room(RoomJID, Alice2, AliceNick),
  766:     escalus:wait_for_stanzas(Bob, 2),
  767:     % Send message
  768:     Res = execute_user(user_send_private_message_body(RoomJID, Message, BobNick, <<"res2">>),
  769:                        Alice, Config),
  770:     assert_success(?SEND_PRIV_MESG_PATH, Res),
  771:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
  772:                               escalus:wait_for_stanza(Bob)).
  773: 
  774: user_without_session_send_message_to_room(Config) ->
  775:     muc_helper:story_with_room(Config, [], [{alice, 1}],
  776:                                fun user_without_session_send_message_to_room_story/2).
  777: 
  778: user_without_session_send_message_to_room_story(Config, Alice) ->
  779:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  780:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
  781:     {exit, _} = rpc(mim(), ejabberd_c2s, terminate_session, [JID, <<"Kicked">>]),
  782:     % Send message
  783:     Res = execute_user(user_send_message_to_room_body(RoomJID, <<"Hello!">>, null), Alice, Config),
  784:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have any session">>)).
  785: 
  786: user_get_room_config(Config) ->
  787:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  788:                                fun user_get_room_config_story/3).
  789: 
  790: user_get_room_config_story(Config, Alice, Bob) ->
  791:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  792:     Res = execute_user(get_room_config_body(RoomJID), Alice, Config),
  793:     assert_default_room_config(Res),
  794:     % Not an owner tries to get room config
  795:     Res2 = execute_user(get_room_config_body(RoomJID), Bob, Config),
  796:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)).
  797: 
  798: user_try_get_nonexistent_room_config(Config) ->
  799:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  800:                                     fun user_try_get_nonexistent_room_config_story/2).
  801: 
  802: user_try_get_nonexistent_room_config_story(Config, Alice) ->
  803:     Res = execute_user(get_room_config_body(?NONEXISTENT_ROOM), Alice, Config),
  804:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  805: 
  806: user_change_room_config(Config) ->
  807:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  808:                                fun user_change_room_config_story/3).
  809: 
  810: user_change_room_config_story(Config, Alice, Bob) ->
  811:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  812:     Title = <<"aloes">>,
  813:     Description = <<"The chat about aloes">>,
  814:     Public = false,
  815:     RoomConfig = #{title => Title, description => Description, public => Public},
  816:     Res = execute_user(change_room_config_body(RoomJID, RoomConfig), Alice, Config),
  817:     ?assertMatch(#{<<"title">> := Title,
  818:                    <<"description">> := Description,
  819:                    <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)),
  820:     % Not an owner tries to change the room config
  821:     Res2 = execute_user(change_room_config_body(RoomJID, RoomConfig), Bob, Config),
  822:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)).
  823: 
  824: user_try_change_nonexistent_room_config(Config) ->
  825:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  826:                                     fun user_try_change_nonexistent_room_config_story/2).
  827: 
  828: user_try_change_nonexistent_room_config_story(Config, Alice) ->
  829:     RoomConfig = #{title => <<"NewTitle">>},
  830:     Res = execute_user(change_room_config_body(?NONEXISTENT_ROOM, RoomConfig), Alice, Config),
  831:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  832: 
  833: user_list_room_users(Config) ->
  834:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  835:                                fun user_list_room_users_story/3).
  836: 
  837: user_list_room_users_story(Config, Alice, Bob) ->
  838:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  839:     BobNick = <<"Bobek">>,
  840:     AliceNick = <<"Ali">>,
  841:     enter_room(RoomJID, Bob, BobNick),
  842:     enter_room(RoomJID, Alice, AliceNick),
  843:     Res = execute_user(list_room_users_body(RoomJID), Alice, Config),
  844:     ExpectedUsers = [{null, BobNick, <<"PARTICIPANT">>},
  845:                      {null, AliceNick, <<"MODERATOR">>}],
  846:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
  847: 
  848: user_list_room_users_without_anonymous_mode(Config) ->
  849:     muc_helper:story_with_room(Config, [{anonymous, false}], [{alice, 1}, {bob, 1}],
  850:                                fun user_list_room_users_without_anonymous_mode_story/3).
  851: 
  852: user_list_room_users_without_anonymous_mode_story(Config, Alice, Bob) ->
  853:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  854:     BobNick = <<"Bobek">>,
  855:     AliceNick = <<"Ali">>,
  856:     enter_room(RoomJID, Bob, BobNick),
  857:     enter_room(RoomJID, Alice, AliceNick),
  858:     Res = execute_user(list_room_users_body(RoomJID), Alice, Config),
  859:     ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>},
  860:                      {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}],
  861:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
  862: 
  863: user_try_list_nonexistent_room_users(Config) ->
  864:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  865:                                     fun user_try_list_nonexistent_room_users_story/2).
  866: 
  867: user_try_list_nonexistent_room_users_story(Config, Alice) ->
  868:     Res = execute_user(list_room_users_body(?NONEXISTENT_ROOM), Alice, Config),
  869:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  870: 
  871: user_try_list_room_users_without_permission(Config) ->
  872:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
  873:                                fun user_try_list_room_users_without_permission_story/3).
  874: 
  875: user_try_list_room_users_without_permission_story(Config, _Alice, Bob) ->
  876:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  877:     Res = execute_user(list_room_users_body(RoomJID), Bob, Config),
  878:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
  879: 
  880: user_get_room_messages(Config) ->
  881:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  882:                                fun user_get_room_messages_story/3).
  883: 
  884: user_get_room_messages_story(Config, Alice, Bob) ->
  885:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  886:     enter_room(RoomJID, Bob, <<"Bobek">>),
  887:     enter_room(RoomJID, Alice, <<"Ali">>),
  888:     escalus:wait_for_stanzas(Bob, 2),
  889:     execute_user(user_send_message_to_room_body(RoomJID, <<"Hi!">>, null), Bob, Config),
  890:     escalus:wait_for_stanzas(Bob, 1),
  891:     mam_helper:maybe_wait_for_archive(Config),
  892:     Res = execute_user(get_room_messages_body(RoomJID, 50, null), Alice, Config),
  893:     #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} =
  894:         get_ok_value(?GET_MESSAGES_PATH, Res),
  895:     ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)).
  896: 
  897: user_try_get_nonexistent_room_messages(Config) ->
  898:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  899:                                     fun user_try_get_nonexistent_room_messages_story/2).
  900: 
  901: user_try_get_nonexistent_room_messages_story(Config, Alice) ->
  902:     % Non-existent room with non-existent domain
  903:     Res = execute_user(get_room_messages_body(?NONEXISTENT_ROOM, null, null), Alice, Config),
  904:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)),
  905:     % Non-existent room with existent domain
  906:     Res2 = execute_user(get_room_messages_body(?NONEXISTENT_ROOM2, null, null), Alice, Config),
  907:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"not found">>)).
  908: 
  909: user_try_get_room_messages_without_permission(Config) ->
  910:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
  911:                                fun user_try_get_room_messages_without_permission/3).
  912: 
  913: user_try_get_room_messages_without_permission(Config, _Alice, Bob) ->
  914:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  915:     Res = execute_user(get_room_messages_body(RoomJID, null, null), Bob, Config),
  916:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
  917: 
  918: user_owner_set_user_affiliation(Config) ->
  919:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  920:                                fun user_owner_set_user_affiliation/3).
  921: 
  922: user_owner_set_user_affiliation(Config, Alice, Bob) ->
  923:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  924:     % Grant a member affiliation 
  925:     Res = execute_user(set_user_affiliation_body(RoomJID, Bob, member), Alice, Config),
  926:     assert_success(?SET_AFFILIATION_PATH, Res),
  927:     assert_user_affiliation(RoomJID, Bob, member),
  928:     % Grant a member affiliation 
  929:     Res1 = execute_user(set_user_affiliation_body(RoomJID, Bob, admin), Alice, Config),
  930:     assert_success(?SET_AFFILIATION_PATH, Res1),
  931:     assert_user_affiliation(RoomJID, Bob, admin),
  932:     % Grant a owner affiliation
  933:     Res2 = execute_user(set_user_affiliation_body(RoomJID, Bob, owner), Alice, Config),
  934:     assert_success(?SET_AFFILIATION_PATH, Res2),
  935:     assert_user_affiliation(RoomJID, Bob, owner),
  936:     % Revoke affiliation 
  937:     Res3 = execute_user(set_user_affiliation_body(RoomJID, Bob, none), Alice, Config),
  938:     assert_success(?SET_AFFILIATION_PATH, Res3),
  939:     assert_user_affiliation(RoomJID, Bob, none),
  940:     % Ban user
  941:     Res4 = execute_user(set_user_affiliation_body(RoomJID, Bob, outcast), Alice, Config),
  942:     assert_success(?SET_AFFILIATION_PATH, Res4),
  943:     assert_user_affiliation(RoomJID, Bob, outcast).
  944: 
  945: 
  946: user_admin_set_user_affiliation(Config) ->
  947:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}, {kate, 1}],
  948:                                fun user_admin_set_user_affiliation/4).
  949: 
  950: user_admin_set_user_affiliation(Config, Alice, Bob, Kate) ->
  951:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  952:     execute_user(set_user_affiliation_body(RoomJID, Bob, admin), Alice, Config),
  953:     % Grant member affiliation
  954:     Res = execute_user(set_user_affiliation_body(RoomJID, Kate, member), Bob, Config),
  955:     assert_success(?SET_AFFILIATION_PATH, Res),
  956:     assert_user_affiliation(RoomJID, Kate, member),
  957:     % Revoke affiliation
  958:     Res1 = execute_user(set_user_affiliation_body(RoomJID, Kate, none), Bob, Config),
  959:     assert_success(?SET_AFFILIATION_PATH, Res1),
  960:     assert_user_affiliation(RoomJID, Kate, none),
  961:     % Admin cannot grant admin affiliation
  962:     Res2 = execute_user(set_user_affiliation_body(RoomJID, Kate, admin), Bob, Config),
  963:     assert_no_permission(Res2),
  964:     % Admin cannot grant owner affiliation
  965:     Res3 = execute_user(set_user_affiliation_body(RoomJID, Kate, owner), Bob, Config),
  966:     assert_no_permission(Res3),
  967:     % Admin can ban member
  968:     Res4 = execute_user(set_user_affiliation_body(RoomJID, Kate, outcast), Bob, Config),
  969:     assert_success(?SET_AFFILIATION_PATH, Res4),
  970:     assert_user_affiliation(RoomJID, Kate, outcast),
  971:     % Admin cannot ban owner
  972:     Res5 = execute_user(set_user_affiliation_body(RoomJID, Alice, outcast), Bob, Config),
  973:     assert_no_permission(Res5).
  974: 
  975: user_member_set_user_affiliation(Config) ->
  976:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}, {kate, 1}],
  977:                                fun user_member_set_user_affiliation/4).
  978: 
  979: user_member_set_user_affiliation(Config, Alice, Bob, Kate) ->
  980:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  981:     execute_user(set_user_affiliation_body(RoomJID, Bob, member), Alice, Config),
  982:     % Member cannot grant member affiliation
  983:     Res = execute_user(set_user_affiliation_body(RoomJID, Kate, member), Bob, Config),
  984:     assert_no_permission(Res),
  985:     % Member cannot grant member admin affiliation
  986:     Res1 = execute_user(set_user_affiliation_body(RoomJID, Kate, admin), Bob, Config),
  987:     assert_no_permission(Res1),
  988:     % Member cannot grant member owner affiliation
  989:     Res2 = execute_user(set_user_affiliation_body(RoomJID, Kate, owner), Bob, Config),
  990:     assert_no_permission(Res2),
  991:     % Member cannot revoke member affiliation
  992:     execute_user(set_user_affiliation_body(RoomJID, Kate, member), Alice, Config),
  993:     Res3 = execute_user(set_user_affiliation_body(RoomJID, Kate, none), Bob, Config),
  994:     assert_no_permission(Res3).
  995: 
  996: user_try_set_nonexistent_room_affiliation(Config) ->
  997:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  998:                                     fun user_try_set_nonexistent_room_affiliation/2).
  999: 
 1000: user_try_set_nonexistent_room_affiliation(Config, Alice) ->
 1001:     Res = execute_user(set_user_affiliation_body(?NONEXISTENT_ROOM, Alice, none), Alice, Config),
 1002:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1003: 
 1004: user_moderator_set_user_role(Config) ->
 1005:     muc_helper:story_with_room(Config, [{anonymous, false}, {persistent, true}],
 1006:                                [{alice, 1}, {bob, 1}],
 1007:                                fun user_moderator_set_user_role/3).
 1008: 
 1009: user_moderator_set_user_role(Config, Alice, Bob) ->
 1010:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1011:     BobNick = <<"Boobek">>,
 1012:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
 1013:     enter_room(RoomJID, Bob, BobNick),
 1014:     % Change from participant to visitor 
 1015:     Res = execute_user(set_user_role_body(RoomJID, BobNick, visitor), Alice, Config),
 1016:     assert_success(?SET_ROLE_PATH, Res),
 1017:     assert_user_role(RoomJID, Bob, visitor),
 1018:     % Change from visitor to participant
 1019:     Res1 = execute_user(set_user_role_body(RoomJID, BobNick, participant), Alice, Config),
 1020:     assert_success(?SET_ROLE_PATH, Res1),
 1021:     assert_user_role(RoomJID, Bob, participant),
 1022:     % Change from participant to moderator 
 1023:     Res2 = execute_user(set_user_role_body(RoomJID, BobNick, moderator), Alice, Config),
 1024:     assert_success(?SET_ROLE_PATH, Res2),
 1025:     assert_user_role(RoomJID, Bob, moderator).
 1026: 
 1027: user_participant_set_user_role(Config) ->
 1028:     muc_helper:story_with_room(Config, [{anonymous, false}, {persistent, true}],
 1029:                                [{alice, 1}, {bob, 1}, {kate, 1}],
 1030:                                fun user_participant_set_user_role/4).
 1031: 
 1032: user_participant_set_user_role(Config, _Alice, Bob, Kate) ->
 1033:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1034:     BobNick = <<"Boobek">>,
 1035:     KateNick = <<"Katek">>,
 1036:     enter_room(RoomJID, Bob, BobNick),
 1037:     enter_room(RoomJID, Kate, KateNick),
 1038:     % Try change from participant to visitor
 1039:     Res = execute_user(set_user_role_body(RoomJID, KateNick, visitor), Bob, Config),
 1040:     assert_no_permission(Res),
 1041:     % Change from participant to participant with success response
 1042:     Res1 = execute_user(set_user_role_body(RoomJID, KateNick, participant), Bob, Config),
 1043:     assert_success(?SET_ROLE_PATH, Res1),
 1044:     assert_user_role(RoomJID, Bob, participant),
 1045:     % Try change from participant to moderator 
 1046:     Res2 = execute_user(set_user_role_body(RoomJID, KateNick, moderator), Bob, Config),
 1047:     assert_no_permission(Res2).
 1048: 
 1049: user_try_set_nonexistent_room_role(Config) ->
 1050:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1051:                                     fun user_try_set_nonexistent_room_role/2).
 1052: 
 1053: user_try_set_nonexistent_room_role(Config, Alice) ->
 1054:     Res = execute_user(set_user_role_body(?NONEXISTENT_ROOM, <<"Ali">>, participant), Alice, Config),
 1055:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1056: 
 1057: user_can_enter_room(Config) ->
 1058:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun user_can_enter_room/2).
 1059: 
 1060: user_can_enter_room(Config, Alice) ->
 1061:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1062:     Nick = <<"ali">>,
 1063:     JID = jid:from_binary(escalus_utils:jid_to_lower(escalus_client:full_jid(Alice))),
 1064:     Resource = escalus_client:resource(Alice),
 1065:     Res = execute_user(user_enter_room_body(RoomJID, Nick, Resource, null), Alice, Config),
 1066:     assert_success(?ENTER_ROOM_PATH, Res),
 1067:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)).
 1068:     
 1069: user_can_enter_room_with_password(Config) ->
 1070:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
 1071:                                [{alice, 1}, {bob, 1}],
 1072:                                fun user_can_enter_room_with_password/3).
 1073: 
 1074: user_can_enter_room_with_password(Config, Alice, Bob) ->
 1075:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1076:     Nick = <<"ali">>,
 1077:     JID = jid:from_binary(escalus_utils:jid_to_lower(escalus_client:full_jid(Alice))),
 1078:     Resource = escalus_client:resource(Alice),
 1079:     % Alice enter room with password
 1080:     Res = execute_user(user_enter_room_body(RoomJID, Nick, Resource, ?PASSWORD), Alice, Config),
 1081:     assert_success(?ENTER_ROOM_PATH, Res),
 1082:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)),
 1083:     % Bob try enter room without password
 1084:     Res1 = execute_user(user_enter_room_body(RoomJID, <<"Bobek">>, Resource, null), Bob, Config),
 1085:     assert_success(?ENTER_ROOM_PATH, Res1),
 1086:     ?assertMatch([_], get_room_users(RoomJID)),
 1087:     % Bob enter room with password
 1088:     Res2 = execute_user(user_enter_room_body(RoomJID, <<"Bobek">>, Resource, ?PASSWORD), Bob, Config),
 1089:     assert_success(?ENTER_ROOM_PATH, Res2),
 1090:     ?assertMatch([_, _], get_room_users(RoomJID)).
 1091: 
 1092: user_can_exit_room(Config) ->
 1093:     muc_helper:story_with_room(Config, [{persistent, true}], [{alice, 1}],
 1094:                                fun user_can_exit_room/2).
 1095: 
 1096: user_can_exit_room(Config, Alice) ->
 1097:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1098:     Nick = <<"ali">>,
 1099:     Resource = escalus_client:resource(Alice),
 1100:     enter_room(RoomJID, Alice, Nick),
 1101:     ?assertMatch([_], get_room_users(RoomJID)),
 1102:     Res = execute_user(user_exit_room_body(RoomJID, Nick, Resource), Alice, Config),
 1103:     assert_success(?EXIT_ROOM_PATH, Res),
 1104:     ?assertMatch([], get_room_users(RoomJID)).
 1105: 
 1106: user_list_room_affiliations(Config) ->
 1107:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1108:                                fun user_list_room_affiliations/3).
 1109: 
 1110: user_list_room_affiliations(Config, Alice, Bob) ->
 1111:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1112:     BobNick = <<"Bobek">>,
 1113:     AliceNick = <<"Ali">>,
 1114:     enter_room(RoomJID, Bob, BobNick),
 1115:     enter_room(RoomJID, Alice, AliceNick),
 1116:     AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
 1117:     BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
 1118:     % List all owners
 1119:     Res = execute_user(list_room_affiliations_body(RoomJID, owner), Alice, Config),
 1120:     ?assertMatch([#{<<"jid">> := AliceJID, <<"affiliation">> := <<"OWNER">>}],
 1121:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res)),
 1122:     % List all members
 1123:     execute_user(set_user_affiliation_body(RoomJID, Bob, member), Alice, Config),
 1124:     Res1 = execute_user(list_room_affiliations_body(RoomJID, member), Alice, Config),
 1125:     ?assertMatch([#{<<"jid">> := BobJID, <<"affiliation">> := <<"MEMBER">>}],
 1126:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res1)),
 1127:     % List all
 1128:     Res2 = execute_user(list_room_affiliations_body(RoomJID, null), Alice, Config),
 1129:     ?assertMatch([_, _], get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res2)).
 1130: 
 1131: user_try_list_room_affiliations_without_permission(Config) ->
 1132:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
 1133:                                fun user_try_list_room_affiliations_without_permission/3).
 1134: 
 1135: user_try_list_room_affiliations_without_permission(Config, _Alice, Bob) ->
 1136:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1137:     Res = execute_user(list_room_affiliations_body(RoomJID, null), Bob, Config),
 1138:     assert_no_permission(Res).
 1139: 
 1140: user_try_list_nonexistent_room_affiliations(Config) ->
 1141:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1142:                                     fun user_try_list_nonexistent_room_affiliations/2).
 1143: 
 1144: user_try_list_nonexistent_room_affiliations(Config, Alice) ->
 1145:     Res = execute_user(list_room_affiliations_body(?NONEXISTENT_ROOM, null), Alice, Config),
 1146:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1147: 
 1148: %% Helpers
 1149: 
 1150: assert_no_full_jid({{<<"400">>,<<"Bad Request">>},
 1151:                     #{<<"errors">> := [#{<<"message">> := Msg}]}}) ->
 1152:     ?assertNotEqual(nomatch, binary:match(Msg, <<"jid_without_resource">>)).
 1153: 
 1154: assert_no_permission(Res) ->
 1155:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
 1156: 
 1157: assert_success(Path, Res) ->
 1158:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res), <<"successfully">>)).
 1159: 
 1160: get_room_affiliation(RoomJID, Aff) ->
 1161:     {ok, Affs} = rpc(mim(), mod_muc_api, get_room_affiliations, [RoomJID, Aff]),
 1162:     Affs.
 1163: 
 1164: get_room_users(RoomJID) ->
 1165:     {ok, Users} = rpc(mim(), mod_muc_api, get_room_users, [RoomJID]),
 1166:     Users.
 1167: 
 1168: assert_user_role(RoomJID, User, Role) ->
 1169:     UserJID = jid:from_binary(escalus_client:full_jid(User)),
 1170:     ?assert(lists:any(fun(#{jid := JID, role := Role2}) ->
 1171:                               Role =:= Role2 andalso jid:are_bare_equal(JID, UserJID) end,
 1172:                       get_room_users(RoomJID))).
 1173: 
 1174: assert_user_affiliation(RoomJID, User, none) ->
 1175:     Affs = get_room_affiliation(RoomJID, undefined),
 1176:     UserSimpleJID = jid:to_lower(user_to_jid(User)),
 1177:     ?assertNot(lists:any(fun({U, _}) -> U == UserSimpleJID end, Affs));
 1178: assert_user_affiliation(RoomJID, User, Aff) ->
 1179:     Affs = get_room_affiliation(RoomJID, Aff),
 1180:     Elem = {jid:to_lower(user_to_jid(User)), Aff},
 1181:     ?assert(lists:member(Elem, Affs)).
 1182: 
 1183: rand_name() ->
 1184:     rpc(mim(), mongoose_bin, gen_from_crypto, []).
 1185: 
 1186: -spec assert_room_users([{jid:jid(), binary(), binary()}], [map()]) -> ok.
 1187: assert_room_users(Expected, Actual) ->
 1188:     ActualTuples = [{JID, Nick, Role} || #{<<"jid">> := JID, <<"role">> := Role, <<"nick">> := Nick} <- Actual],
 1189:     ?assertEqual(lists:sort(Expected), lists:sort(ActualTuples)).
 1190: 
 1191: assert_is_message_correct(RoomJID, SenderNick, Type, Text, ReceivedMessage) ->
 1192:     escalus_pred:is_message(ReceivedMessage),
 1193:     From = jid:to_binary(jid:replace_resource(RoomJID, SenderNick)),
 1194:     From = exml_query:attr(ReceivedMessage, <<"from">>),
 1195:     Type = exml_query:attr(ReceivedMessage, <<"type">>),
 1196:     Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content=Text}]},
 1197:     Body = exml_query:subelement(ReceivedMessage, <<"body">>).
 1198: 
 1199: enter_room(RoomJID, User, Nick) ->
 1200:     JID = jid:to_binary(jid:replace_resource(RoomJID, Nick)),
 1201:     Pres = escalus_stanza:to(escalus_stanza:presence(<<"available">>, []), JID),
 1202:     escalus:send(User, Pres),
 1203:     escalus:wait_for_stanza(User).
 1204: 
 1205: contain_room(Name, #{<<"rooms">> := Rooms}) ->
 1206:     contain_room(Name, Rooms);
 1207: contain_room(Name, Rooms) when is_list(Rooms) -> 
 1208:     lists:any(fun(#{<<"title">> := T}) -> T =:= Name end, Rooms).
 1209: 
 1210: assert_default_room_config(Response) ->
 1211:     ?assertMatch(#{<<"title">> := <<>>,
 1212:                    <<"description">> := <<>>,
 1213:                    <<"allowChangeSubject">> := true,
 1214:                    <<"allowQueryUsers">> := true,
 1215:                    <<"allowPrivateMessages">> := true,
 1216:                    <<"allowVisitorStatus">> := true,
 1217:                    <<"allowVisitorNickchange">> := true,
 1218:                    <<"public">> := true,
 1219:                    <<"publicList">> := true,
 1220:                    <<"persistent">> := false,
 1221:                    <<"moderated">> := true,
 1222:                    <<"membersByDefault">> := true,
 1223:                    <<"membersOnly">> := false,
 1224:                    <<"allowUserInvites">> := false,
 1225:                    <<"allowMultipleSession">> := false,
 1226:                    <<"passwordProtected">> := false,
 1227:                    <<"password">> := <<>>,
 1228:                    <<"anonymous">> := true,
 1229:                    <<"mayGetMemberList">> := [],
 1230:                    <<"maxUsers">> := 200,
 1231:                    <<"logging">> := false}, get_ok_value(?GET_ROOM_CONFIG_PATH, Response)).
 1232: 
 1233: atom_to_enum_item(null) -> null;
 1234: atom_to_enum_item(Atom) -> list_to_binary(string:to_upper(atom_to_list(Atom))).
 1235: 
 1236: %% Request bodies
 1237: 
 1238: admin_create_instant_room_body(MUCDomain, Name, Owner, Nick) ->
 1239:     Query = <<"mutation M1($mucDomain: String!, $name: String!, $owner: JID!, $nick: String!)
 1240:               { muc { createInstantRoom(mucDomain: $mucDomain, name: $name, owner: $owner, nick: $nick)
 1241:               { jid title private usersNumber } } }">>,
 1242:     OpName = <<"M1">>,
 1243:     Vars = #{mucDomain => MUCDomain, name => Name, owner => user_to_bin(Owner), nick => Nick},
 1244:     #{query => Query, operationName => OpName, variables => Vars}.
 1245: 
 1246: admin_invite_user_body(Room, Sender, Recipient, Reason) ->
 1247:     Query = <<"mutation M1($room: JID!, $sender: JID!, $recipient: JID!, $reason: String)
 1248:               { muc { inviteUser(room: $room, sender: $sender, recipient: $recipient, reason: $reason) } }">>,
 1249:     OpName = <<"M1">>,
 1250:     Vars = #{room => jid:to_binary(Room), sender => user_to_bin(Sender),
 1251:              recipient => user_to_bin(Recipient), reason => Reason},
 1252:     #{query => Query, operationName => OpName, variables => Vars}.
 1253: 
 1254: kick_user_body(Room, Nick, Reason) ->
 1255:     Query = <<"mutation M1($room: JID!, $nick: String!, $reason: String)
 1256:               { muc { kickUser(room: $room, nick: $nick, reason: $reason) } }">>,
 1257:     OpName = <<"M1">>,
 1258:     Vars = #{room => jid:to_binary(Room), nick => Nick, reason => Reason},
 1259:     #{query => Query, operationName => OpName, variables => Vars}.
 1260: 
 1261: admin_send_message_to_room_body(Room, From, Body) ->
 1262:     Query = <<"mutation M1($room: JID!, $from: FullJID!, $body: String!)
 1263:               { muc { sendMessageToRoom(room: $room, from: $from, body: $body) } }">>,
 1264:     OpName = <<"M1">>,
 1265:     Vars = #{room => jid:to_binary(Room), from => user_to_full_bin(From), body => Body},
 1266:     #{query => Query, operationName => OpName, variables => Vars}.
 1267: 
 1268: admin_send_private_message_body(Room, From, ToNick, Body) ->
 1269:     Query = <<"mutation M1($room: JID!, $from: FullJID!, $toNick: String!, $body: String!)
 1270:               { muc { sendPrivateMessage(room: $room, from: $from, toNick: $toNick, body: $body) } }">>,
 1271:     OpName = <<"M1">>,
 1272:     Vars = #{room => jid:to_binary(Room), from => user_to_full_bin(From),
 1273:              toNick => ToNick, body => Body},
 1274:     #{query => Query, operationName => OpName, variables => Vars}.
 1275: 
 1276: 
 1277: admin_enter_room_body(Room, User, Nick, Password) ->
 1278:     Query = <<"mutation M1($room: JID!, $user: FullJID!, $nick: String! $password: String)
 1279:                { muc { enterRoom(room: $room, user: $user, nick: $nick, password: $password) } }">>,
 1280:     OpName = <<"M1">>,
 1281:     Vars = #{room => jid:to_binary(Room), user => user_to_full_bin(User), nick => Nick, password => Password},
 1282:     #{query => Query, operationName => OpName, variables => Vars}.
 1283: 
 1284: admin_exit_room_body(Room, User, Nick) ->
 1285:     Query = <<"mutation M1($room: JID!, $user: FullJID!, $nick: String!)
 1286:                { muc { exitRoom(room: $room, user: $user, nick: $nick) } }">>,
 1287:     OpName = <<"M1">>,
 1288:     Vars = #{room => jid:to_binary(Room), user => user_to_full_bin(User), nick => Nick},
 1289:     #{query => Query, operationName => OpName, variables => Vars}.
 1290: 
 1291: delete_room_body(Room, Reason) ->
 1292:     Query = <<"mutation M1($room: JID!, $reason: String)
 1293:               { muc { deleteRoom(room: $room, reason: $reason) } }">>,
 1294:     OpName = <<"M1">>,
 1295:     Vars = #{room => jid:to_binary(Room), reason => Reason},
 1296:     #{query => Query, operationName => OpName, variables => Vars}.
 1297: 
 1298: change_room_config_body(Room, Config) ->
 1299:     Query = <<"mutation M1($room: JID!, $config: MUCRoomConfigInput!)
 1300:               { muc { changeRoomConfiguration(room: $room, config: $config)
 1301:               { title description allowChangeSubject allowQueryUsers allowPrivateMessages
 1302:                 allowVisitorStatus allowVisitorNickchange public publicList persistent
 1303:                 moderated membersByDefault membersOnly allowUserInvites allowMultipleSession
 1304:                 passwordProtected password anonymous mayGetMemberList maxUsers logging } } }">>,
 1305:     OpName = <<"M1">>,
 1306:     Vars = #{room => jid:to_binary(Room), config => Config},
 1307:     #{query => Query, operationName => OpName, variables => Vars}.
 1308: 
 1309: admin_list_rooms_body(MUCDomain, From, Limit, Index) ->
 1310:     Query = <<"query Q1($mucDomain: String!, $from: JID, $limit: Int, $index: Int)
 1311:               { muc { listRooms(mucDomain: $mucDomain, from: $from, limit: $limit, index: $index)
 1312:               { rooms { jid title private usersNumber } count index first last} } }">>,
 1313:     OpName = <<"Q1">>,
 1314:     Vars = #{mucDomain => MUCDomain, from => user_to_bin(From), limit => Limit, index => Index},
 1315:     #{query => Query, operationName => OpName, variables => Vars}.
 1316: 
 1317: get_room_config_body(Room) ->
 1318:     Query = <<"query Q1($room: JID!)
 1319:               { muc { getRoomConfig(room: $room)
 1320:               { title description allowChangeSubject allowQueryUsers allowPrivateMessages
 1321:                 allowVisitorStatus allowVisitorNickchange public publicList persistent
 1322:                 moderated membersByDefault membersOnly allowUserInvites allowMultipleSession
 1323:                 passwordProtected password anonymous mayGetMemberList maxUsers logging } } }">>,
 1324:     OpName = <<"Q1">>,
 1325:     Vars = #{room => jid:to_binary(Room)},
 1326:     #{query => Query, operationName => OpName, variables => Vars}.
 1327: 
 1328: list_room_users_body(RoomJID) ->
 1329:     Query = <<"query Q1($room: JID!)
 1330:               { muc { listRoomUsers(room: $room)
 1331:               { jid nick role } } }">>,
 1332:     OpName = <<"Q1">>,
 1333:     Vars = #{room => jid:to_binary(RoomJID)},
 1334:     #{query => Query, operationName => OpName, variables => Vars}.
 1335: 
 1336: get_room_messages_body(RoomJID, PageSize, Before) ->
 1337:     Query = <<"query Q1($room: JID!, $pageSize: Int, $before: DateTime)
 1338:               { muc { getRoomMessages(room: $room, pageSize: $pageSize, before: $before)
 1339:               { stanzas { stanza } limit } } }">>,
 1340:     OpName = <<"Q1">>,
 1341:     Vars = #{<<"room">> => jid:to_binary(RoomJID), <<"pageSize">> => PageSize,
 1342:              <<"before">> => Before},
 1343:     #{query => Query, operationName => OpName, variables => Vars}.
 1344: 
 1345: user_list_rooms_body(MUCDomain, Limit, Index) ->
 1346:     Query = <<"query Q1($mucDomain: String!, $limit: Int, $index: Int)
 1347:               { muc { listRooms(mucDomain: $mucDomain, limit: $limit, index: $index)
 1348:               { rooms { jid title private usersNumber } count index first last} } }">>,
 1349:     OpName = <<"Q1">>,
 1350:     Vars = #{mucDomain => MUCDomain, limit => Limit, index => Index},
 1351:     #{query => Query, operationName => OpName, variables => Vars}.
 1352: 
 1353: user_send_message_to_room_body(Room, Body, Resource) ->
 1354:     Query = <<"mutation M1($room: JID!, $body: String!, $resource: String)
 1355:               { muc { sendMessageToRoom(room: $room, body: $body, resource: $resource) } }">>,
 1356:     OpName = <<"M1">>,
 1357:     Vars = #{room => jid:to_binary(Room), body => Body, resource => Resource},
 1358:     #{query => Query, operationName => OpName, variables => Vars}.
 1359: 
 1360: user_send_private_message_body(Room, Body, ToNick, Resource) ->
 1361:     Query = <<"mutation M1($room: JID!, $body: String!, $toNick: String!, $resource: String)
 1362:               { muc { sendPrivateMessage(room: $room, body: $body, toNick: $toNick, resource: $resource) } }">>,
 1363:     OpName = <<"M1">>,
 1364:     Vars = #{room => jid:to_binary(Room), body => Body, toNick => ToNick, resource => Resource},
 1365:     #{query => Query, operationName => OpName, variables => Vars}.
 1366: 
 1367: 
 1368: user_create_instant_room_body(MUCDomain, Name, Nick) ->
 1369:     Query = <<"mutation M1($mucDomain: String!, $name: String!, $nick: String!)
 1370:               { muc { createInstantRoom(mucDomain: $mucDomain, name: $name, nick: $nick)
 1371:               { jid title private usersNumber } } }">>,
 1372:     OpName = <<"M1">>,
 1373:     Vars = #{mucDomain => MUCDomain, name => Name, nick => Nick},
 1374:     #{query => Query, operationName => OpName, variables => Vars}.
 1375: 
 1376: user_invite_user_body(Room, Recipient, Reason) ->
 1377:     Query = <<"mutation M1($room: JID!, $recipient: JID!, $reason: String)
 1378:               { muc { inviteUser(room: $room, recipient: $recipient, reason: $reason) } }">>,
 1379:     OpName = <<"M1">>,
 1380:     Vars = #{room => jid:to_binary(Room), recipient => user_to_bin(Recipient), reason => Reason},
 1381:     #{query => Query, operationName => OpName, variables => Vars}.
 1382: 
 1383: set_user_affiliation_body(Room, User, Aff) ->
 1384:     Query = <<"mutation M1($room: JID!, $user: JID!, $affiliation: MUCAffiliation!)
 1385:                { muc { setUserAffiliation(room: $room, user: $user, affiliation: $affiliation) } }">>,
 1386:     OpName = <<"M1">>,
 1387:     Vars = #{room => jid:to_binary(Room), user => user_to_bin(User),
 1388:              affiliation => atom_to_enum_item(Aff)},
 1389:     #{query => Query, operationName => OpName, variables => Vars}.
 1390: 
 1391: set_user_role_body(Room, User, Role) ->
 1392:     Query = <<"mutation M1($room: JID!, $nick: String!, $role: MUCRole!)
 1393:                { muc { setUserRole(room: $room, nick: $nick, role: $role) } }">>,
 1394:     OpName = <<"M1">>,
 1395:     Vars = #{room => jid:to_binary(Room), nick => user_to_bin(User),
 1396:              role => atom_to_enum_item(Role)},
 1397:     #{query => Query, operationName => OpName, variables => Vars}.
 1398: 
 1399: user_enter_room_body(Room, Nick, Resource, Password) ->
 1400:     Query = <<"mutation M1($room: JID!, $nick: String!, $resource: String!, $password: String)
 1401:                { muc { enterRoom(room: $room, nick: $nick, resource: $resource, password: $password) } }">>,
 1402:     OpName = <<"M1">>,
 1403:     Vars = #{room => jid:to_binary(Room), resource => Resource, password => Password, nick => Nick},
 1404:     #{query => Query, operationName => OpName, variables => Vars}.
 1405: 
 1406: user_exit_room_body(Room, Nick, Resource) ->
 1407:     Query = <<"mutation M1($room: JID!, $nick: String!, $resource: String!)
 1408:                { muc { exitRoom(room: $room, nick: $nick, resource: $resource) } }">>,
 1409:     OpName = <<"M1">>,
 1410:     Vars = #{room => jid:to_binary(Room), resource => Resource, nick => Nick},
 1411:     #{query => Query, operationName => OpName, variables => Vars}.
 1412: 
 1413: list_room_affiliations_body(Room, Aff) ->
 1414:     Query = <<"query Q1($room: JID!, $affiliation: MUCAffiliation)
 1415:                { muc { listRoomAffiliations(room: $room, affiliation: $affiliation)
 1416:                { jid affiliation } } }">>,
 1417:     OpName = <<"Q1">>,
 1418:     Vars = #{room => jid:to_binary(Room), affiliation => atom_to_enum_item(Aff)},
 1419:     #{query => Query, operationName => OpName, variables => Vars}.