1: -module(graphql_muc_SUITE).
    2: 
    3: -compile([export_all, nowarn_export_all]).
    4: 
    5: -import(common_helper, [unprep/1]).
    6: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4, subhost_pattern/1]).
    7: -import(graphql_helper, [execute_command/4, execute_user_command/5, get_ok_value/2, get_err_msg/1,
    8:                          get_coercion_err_msg/1, user_to_bin/1, user_to_full_bin/1, user_to_jid/1,
    9:                          get_unauthorized/1, get_not_loaded/1]).
   10: 
   11: -include_lib("common_test/include/ct.hrl").
   12: -include_lib("eunit/include/eunit.hrl").
   13: -include_lib("exml/include/exml.hrl").
   14: -include_lib("jid/include/jid.hrl").
   15: 
   16: suite() ->
   17:     require_rpc_nodes([mim]) ++ escalus:suite().
   18: 
   19: all() ->
   20:     [{group, user},
   21:      {group, admin_http},
   22:      {group, admin_cli},
   23:      {group, domain_admin_muc}].
   24: 
   25: groups() ->
   26:     [{user, [], user_groups()},
   27:      {admin_http, [], admin_groups()},
   28:      {admin_cli, [], admin_groups()},
   29:      {admin_muc_configured, [], admin_muc_tests()},
   30:      {admin_muc_and_mam_configured, [], admin_muc_with_mam_tests()},
   31:      {admin_muc_not_configured, [], admin_muc_not_configured_tests()},
   32:      {user_muc_configured, [parallel], user_muc_tests()},
   33:      {user_muc_and_mam_configured, [parallel], user_muc_with_mam_tests()},
   34:      {user_muc_not_configured, [parallel], user_muc_not_configured_tests()},
   35:      {domain_admin_muc, [], domain_admin_muc_tests()}].
   36: 
   37: user_groups() ->
   38:     [{group, user_muc_configured},
   39:      {group, user_muc_and_mam_configured},
   40:      {group, user_muc_not_configured}].
   41: 
   42: admin_groups() ->
   43:     [{group, admin_muc_configured},
   44:      {group, admin_muc_and_mam_configured},
   45:      {group, admin_muc_not_configured}].
   46: 
   47: user_muc_tests() ->
   48:     [user_create_and_delete_room,
   49:      user_create_room_with_unprepped_name,
   50:      user_try_delete_nonexistent_room,
   51:      user_try_delete_room_by_not_owner,
   52:      user_try_create_instant_room_with_nonexistent_domain,
   53:      user_try_create_instant_room_with_invalid_args,
   54:      user_list_rooms,
   55:      user_try_list_rooms_for_nonexistent_domain,
   56:      user_list_room_users,
   57:      user_list_room_users_without_anonymous_mode,
   58:      user_try_list_room_users_without_permission,
   59:      user_try_list_nonexistent_room_users,
   60:      user_change_room_config,
   61:      user_try_change_nonexistent_room_config,
   62:      user_get_room_config,
   63:      user_try_get_nonexistent_room_config,
   64:      user_invite_user,
   65:      user_kick_user,
   66:      user_try_kick_user_from_nonexistent_room,
   67:      user_try_kick_user_without_moderator_resource,
   68:      user_send_message_to_room,
   69:      user_send_message_to_room_with_specified_res,
   70:      user_send_private_message,
   71:      user_without_session_send_message_to_room,
   72:      user_owner_set_user_affiliation,
   73:      user_admin_set_user_affiliation,
   74:      user_member_set_user_affiliation,
   75:      user_try_set_nonexistent_room_affiliation,
   76:      user_moderator_set_user_role,
   77:      user_participant_set_user_role,
   78:      user_try_set_nonexistent_room_role,
   79:      user_can_enter_room,
   80:      user_cannot_enter_room_with_invalid_resource,
   81:      user_can_enter_room_with_password,
   82:      user_can_exit_room,
   83:      user_list_room_affiliations,
   84:      user_try_list_room_affiliations_without_permission,
   85:      user_try_list_nonexistent_room_affiliations,
   86:      user_get_room_messages_muc_or_mam_not_configured
   87:     ].
   88: 
   89: user_muc_with_mam_tests() ->
   90:     [user_get_room_messages,
   91:      user_shouldnt_store_messages_in_muc_light,
   92:      user_try_get_nonexistent_room_messages,
   93:      user_try_get_room_messages_without_permission].
   94: 
   95: user_muc_not_configured_tests() ->
   96:     [user_delete_room_muc_not_configured,
   97:      user_list_room_users_muc_not_configured,
   98:      user_change_room_config_muc_not_configured,
   99:      user_get_room_config_muc_not_configured,
  100:      user_invite_user_muc_not_configured,
  101:      user_kick_user_muc_not_configured,
  102:      user_send_message_to_room_muc_not_configured,
  103:      user_send_private_message_muc_not_configured,
  104:      user_get_room_messages_muc_or_mam_not_configured,
  105:      user_owner_set_user_affiliation_muc_not_configured,
  106:      user_moderator_set_user_role_muc_not_configured,
  107:      user_can_enter_room_muc_not_configured,
  108:      user_can_exit_room_muc_not_configured,
  109:      user_list_room_affiliations_muc_not_configured].
  110: 
  111: admin_muc_tests() ->
  112:     [admin_list_rooms,
  113:      admin_list_rooms_with_invalid_args,
  114:      admin_create_and_delete_room,
  115:      admin_create_room_with_unprepped_name,
  116:      admin_try_create_instant_room_with_nonexistent_domain,
  117:      admin_try_create_instant_room_with_nonexistent_user,
  118:      admin_try_create_instant_room_with_invalid_args,
  119:      admin_try_delete_nonexistent_room,
  120:      admin_try_delete_room_with_nonexistent_domain,
  121:      admin_try_list_rooms_for_nonexistent_domain,
  122:      admin_list_room_users,
  123:      admin_try_list_users_from_nonexistent_room,
  124:      admin_change_room_config,
  125:      admin_try_change_nonexistent_room_config,
  126:      admin_get_room_config,
  127:      admin_try_get_nonexistent_room_config,
  128:      admin_invite_user,
  129:      admin_invite_user_with_password,
  130:      admin_try_invite_user_to_nonexistent_room,
  131:      admin_kick_user,
  132:      admin_try_kick_user_from_nonexistent_room,
  133:      admin_try_kick_user_from_room_without_moderators,
  134:      admin_send_message_to_room,
  135:      admin_send_private_message,
  136:      admin_set_user_affiliation,
  137:      admin_try_set_nonexistent_room_user_affiliation,
  138:      admin_set_user_role,
  139:      admin_try_set_nonexistent_room_user_role,
  140:      admin_try_set_nonexistent_nick_role,
  141:      admin_try_set_user_role_in_room_without_moderators,
  142:      admin_make_user_enter_room,
  143:      admin_make_user_enter_room_with_password,
  144:      admin_make_user_enter_room_bare_jid,
  145:      admin_make_user_exit_room,
  146:      admin_make_user_exit_room_bare_jid,
  147:      admin_list_room_affiliations,
  148:      admin_try_list_nonexistent_room_affiliations,
  149:      admin_get_room_messages_muc_or_mam_not_configured
  150:     ].
  151: 
  152: admin_muc_with_mam_tests() ->
  153:     [admin_get_room_messages,
  154:      admin_try_get_nonexistent_room_messages].
  155: 
  156: admin_muc_not_configured_tests() ->
  157:     [admin_delete_room_muc_not_configured,
  158:      admin_list_room_users_muc_not_configured,
  159:      admin_change_room_config_muc_not_configured,
  160:      admin_get_room_config_muc_not_configured,
  161:      admin_invite_user_muc_not_configured,
  162:      admin_kick_user_muc_not_configured,
  163:      admin_send_message_to_room_muc_not_configured,
  164:      admin_send_private_message_muc_not_configured,
  165:      admin_get_room_messages_muc_or_mam_not_configured,
  166:      admin_set_user_affiliation_muc_not_configured,
  167:      admin_set_user_role_muc_not_configured,
  168:      admin_make_user_enter_room_muc_not_configured,
  169:      admin_make_user_exit_room_muc_not_configured,
  170:      admin_list_room_affiliations_muc_not_configured].
  171: 
  172: domain_admin_muc_tests() ->
  173:     [admin_list_rooms,
  174:      admin_create_and_delete_room,
  175:      admin_create_room_with_unprepped_name,
  176:      admin_try_create_instant_room_with_nonexistent_domain,
  177:      admin_try_delete_nonexistent_room,
  178:      domain_admin_create_and_delete_room_no_permission,
  179:      domain_admin_list_rooms_no_permission,
  180:      admin_list_room_users,
  181:      domain_admin_list_room_users_no_permission,
  182:      admin_change_room_config,
  183:      domain_admin_change_room_config_no_permission,
  184:      admin_get_room_config,
  185:      domain_admin_get_room_config_no_permission,
  186:      admin_invite_user,
  187:      admin_invite_user_with_password,
  188:      admin_try_invite_user_to_nonexistent_room,
  189:      domain_admin_invite_user_no_permission,
  190:      admin_kick_user,
  191:      admin_try_kick_user_from_room_without_moderators,
  192:      domain_admin_kick_user_no_permission,
  193:      admin_send_message_to_room,
  194:      domain_admin_send_message_to_room_no_permission,
  195:      admin_send_private_message,
  196:      domain_admin_send_private_message_no_permission,
  197:      admin_get_room_messages,
  198:      domain_admin_get_room_messages_no_permission,
  199:      admin_set_user_affiliation,
  200:      domain_admin_set_user_affiliation_no_permission,
  201:      admin_set_user_role,
  202:      admin_try_set_nonexistent_nick_role,
  203:      admin_try_set_user_role_in_room_without_moderators,
  204:      domain_admin_set_user_role_no_permission,
  205:      admin_make_user_enter_room,
  206:      admin_make_user_enter_room_with_password,
  207:      admin_make_user_enter_room_bare_jid,
  208:      domain_admin_make_user_enter_room_no_permission,
  209:      admin_make_user_exit_room,
  210:      admin_make_user_exit_room_bare_jid,
  211:      domain_admin_make_user_exit_room_no_permission,
  212:      admin_list_room_affiliations,
  213:      domain_admin_list_room_affiliations_no_permission
  214:     ].
  215: 
  216: init_per_suite(Config) ->
  217:     HostType = domain_helper:host_type(),
  218:     SecondaryHostType = domain_helper:secondary_host_type(),
  219:     Config2 = escalus:init_per_suite(Config),
  220:     Config3 = dynamic_modules:save_modules(HostType, Config2),
  221:     Config4 = dynamic_modules:save_modules(SecondaryHostType, Config3),
  222:     Config5 = ejabberd_node_utils:init(mim(), Config4),
  223:     dynamic_modules:restart(HostType, mod_disco,
  224:                             config_parser_helper:default_mod_config(mod_disco)),
  225:     Config5.
  226: 
  227: end_per_suite(Config) ->
  228:     escalus_fresh:clean(),
  229:     mongoose_helper:ensure_muc_clean(),
  230:     ensure_muc_stopped(),
  231:     dynamic_modules:restore_modules(Config),
  232:     escalus:end_per_suite(Config).
  233: 
  234: init_per_group(admin_http, Config) ->
  235:     graphql_helper:init_admin_handler(Config);
  236: init_per_group(admin_cli, Config) ->
  237:     graphql_helper:init_admin_cli(Config);
  238: init_per_group(domain_admin_muc, Config) ->
  239:     maybe_enable_mam(),
  240:     ensure_muc_started(),
  241:     graphql_helper:init_domain_admin_handler(Config);
  242: init_per_group(user, Config) ->
  243:     graphql_helper:init_user(Config);
  244: init_per_group(Group, Config) when Group =:= admin_muc_configured;
  245:                                    Group =:= user_muc_configured ->
  246:     disable_mam(),
  247:     ensure_muc_started(),
  248:     Config;
  249: init_per_group(Group, Config) when Group =:= admin_muc_and_mam_configured;
  250:                                    Group =:= user_muc_and_mam_configured ->
  251:     case maybe_enable_mam() of
  252:         true ->
  253:             ensure_muc_started(),
  254:             ensure_muc_light_started(Config);
  255:         false ->
  256:             {skip, "No MAM backend available"}
  257:     end;
  258: init_per_group(Group, Config) when Group =:= admin_muc_not_configured;
  259:                                    Group =:= user_muc_not_configured ->
  260:     maybe_enable_mam(),
  261:     ensure_muc_stopped(),
  262:     Config.
  263: 
  264: disable_mam() ->
  265:     dynamic_modules:ensure_modules(domain_helper:host_type(), [{mod_mam, stopped}]).
  266: 
  267: maybe_enable_mam() ->
  268:     case mam_helper:backend() of
  269:         disabled ->
  270:             false;
  271:         Backend ->
  272:             MAMOpts = mam_helper:config_opts(
  273:                         #{backend => Backend,
  274:                           muc => #{host => subhost_pattern(muc_helper:muc_host_pattern())},
  275:                           async_writer => #{enabled => false}}),
  276:             dynamic_modules:ensure_modules(domain_helper:host_type(), [{mod_mam, MAMOpts}]),
  277:             true
  278:     end.
  279: 
  280: ensure_muc_started() ->
  281:     SecondaryHostType = domain_helper:secondary_host_type(),
  282:     muc_helper:load_muc(),
  283:     muc_helper:load_muc(SecondaryHostType),
  284:     mongoose_helper:ensure_muc_clean().
  285: 
  286: ensure_muc_stopped() ->
  287:     SecondaryHostType = domain_helper:secondary_host_type(),
  288:     muc_helper:unload_muc(),
  289:     muc_helper:unload_muc(SecondaryHostType).
  290: 
  291: ensure_muc_light_started(Config) ->
  292:     MucLightOpts = config_parser_helper:mod_config(mod_muc_light,
  293:         #{rooms_in_rosters => true, config_schema => custom_schema()}),
  294:     HostType = domain_helper:host_type(),
  295:     dynamic_modules:ensure_modules(HostType, [{mod_muc_light, MucLightOpts}]),
  296:     [{muc_light_host, muc_light_helper:muc_host()} | Config].
  297: 
  298: ensure_muc_light_stopped() ->
  299:     HostType = domain_helper:host_type(),
  300:     dynamic_modules:ensure_modules(HostType, [{mod_muc_light, stopped}]).
  301: 
  302: custom_schema() ->
  303:     %% Should be sorted
  304:     [{<<"background">>, <<>>, background, binary},
  305:      {<<"music">>, <<>>, music, binary},
  306:      %% Default fields
  307:      {<<"roomname">>, <<>>, roomname, binary},
  308:      {<<"subject">>, <<"Test">>, subject, binary}].
  309: 
  310: end_per_group(Group, _Config) when Group =:= user;
  311:                                    Group =:= admin_http;
  312:                                    Group =:= domain_admin_muc;
  313:                                    Group =:= admin_cli ->
  314:     graphql_helper:clean();
  315: end_per_group(Group, _Config) when Group =:= admin_muc_and_mam_configured;
  316:                                    Group =:= user_muc_and_mam_configured ->
  317:     ensure_muc_light_stopped(),
  318:     escalus_fresh:clean();
  319: end_per_group(_Group, _Config) ->
  320:     escalus_fresh:clean().
  321: 
  322: init_per_testcase(TC, Config) ->
  323:     escalus:init_per_testcase(TC, Config).
  324: 
  325: end_per_testcase(TC, Config) ->
  326:     escalus:end_per_testcase(TC, Config).
  327: 
  328: -define(CREATE_INSTANT_ROOM_PATH, [data, muc, createInstantRoom]).
  329: -define(LIST_ROOMS_PATH, [data, muc, listRooms]).
  330: -define(INVITE_USER_PATH, [data, muc, inviteUser]).
  331: -define(KICK_USER_PATH, [data, muc, kickUser]).
  332: -define(DELETE_ROOM_PATH, [data, muc, deleteRoom]).
  333: -define(SEND_MESSAGE_PATH, [data, muc, sendMessageToRoom]).
  334: -define(SEND_PRIV_MESG_PATH, [data, muc, sendPrivateMessage]).
  335: -define(GET_MESSAGES_PATH, [data, muc, getRoomMessages]).
  336: -define(LIST_ROOM_USERS_PATH, [data, muc, listRoomUsers]).
  337: -define(LIST_ROOM_AFFILIATIONS_PATH, [data, muc, listRoomAffiliations]).
  338: -define(CHANGE_ROOM_CONFIG_PATH, [data, muc, changeRoomConfiguration]).
  339: -define(GET_ROOM_CONFIG_PATH, [data, muc, getRoomConfig]).
  340: -define(SET_AFFILIATION_PATH, [data, muc, setUserAffiliation]).
  341: -define(SET_ROLE_PATH, [data, muc, setUserRole]).
  342: -define(ENTER_ROOM_PATH, [data, muc, enterRoom]).
  343: -define(EXIT_ROOM_PATH, [data, muc, exitRoom]).
  344: 
  345: -define(NONEXISTENT_ROOM, <<"room@room">>).
  346: -define(NONEXISTENT_ROOM2, <<"room@", (muc_helper:muc_host())/binary>>).
  347: -define(EXTERNAL_DOMAIN_ROOM, <<"external_room@muc.", (domain_helper:secondary_domain())/binary>>).
  348: -define(PASSWORD, <<"pa5sw0rd">>).
  349: 
  350: admin_list_rooms(Config) ->
  351:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun admin_list_rooms_story/3).
  352: 
  353: admin_list_rooms_story(Config, Alice, Bob) ->
  354:     Res0 = list_rooms(muc_helper:muc_host(), Alice, null, null, Config),
  355:     ?assertEqual([], extract_rooms(get_ok_value(?LIST_ROOMS_PATH, Res0))),
  356:     AliceJID = jid:from_binary(escalus_client:short_jid(Alice)),
  357:     BobJID = jid:from_binary(escalus_client:short_jid(Bob)),
  358:     AliceRoom = rand_name(),
  359:     BobRoom = rand_name(),
  360:     muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []),
  361:     muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, [{public_list, false}]),
  362:     Res1 = list_rooms(muc_helper:muc_host(), Alice, null, null, Config),
  363:     Rooms1 = [_, RoomB] = extract_rooms(get_ok_value(?LIST_ROOMS_PATH, Res1)),
  364:     ?assertEqual(lists:sort([AliceRoom, BobRoom]), lists:sort(Rooms1)),
  365:     Res2 = list_rooms(unprep(muc_helper:muc_host()), Alice, null, null, Config),
  366:     ?assertEqual(Rooms1, extract_rooms(get_ok_value(?LIST_ROOMS_PATH, Res2))),
  367:     Res3 = list_rooms(muc_helper:muc_host(), Alice, 1, 1, Config),
  368:     ?assertEqual([RoomB], extract_rooms(get_ok_value(?LIST_ROOMS_PATH, Res3))).
  369: 
  370: admin_list_rooms_with_invalid_args(Config) ->
  371:     Config1 = escalus_fresh:create_users(Config, [{alice, 1}]),
  372:     AliceJid = escalus_users:get_jid(Config1, alice),
  373:     AliceDomain = escalus_users:get_host(Config1, alice),
  374:     Res1 = list_rooms(muc_helper:muc_host(), AliceDomain, null, null, Config1),
  375:     assert_coercion_err(Res1, <<"jid_without_local_part">>),
  376:     Res2 = list_rooms(muc_helper:muc_host(), AliceJid, 0, null, Config1),
  377:     assert_coercion_err(Res2, <<"Value is not a positive integer">>),
  378:     Res3 = list_rooms(muc_helper:muc_host(), AliceJid, null, -1, Config1),
  379:     assert_coercion_err(Res3, <<"Value is not a non-negative integer">>).
  380: 
  381: admin_try_list_rooms_for_nonexistent_domain(Config) ->
  382:     Config1 = escalus_fresh:create_users(Config, [{alice, 1}]),
  383:     AliceJID = escalus_users:get_jid(Config1, alice),
  384:     Res1 = list_rooms(<<"baddomain">>, AliceJID, null, null, Config1),
  385:     ?assertMatch({_, _}, binary:match(get_err_msg(Res1), <<"not found">>)),
  386:     %% Domain instead of the MUC subdomain
  387:     Res2 = list_rooms(domain_helper:domain(), AliceJID, null, null, Config1),
  388:     ?assertMatch({_, _}, binary:match(get_err_msg(Res2), <<"not found">>)).
  389: 
  390: admin_create_and_delete_room(Config) ->
  391:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_create_and_delete_room_story/2).
  392: 
  393: admin_create_and_delete_room_story(Config, Alice) ->
  394:     Name = <<"first-alice-room">>,
  395:     MUCServer = muc_helper:muc_host(),
  396:     RoomJID = jid:make_bare(Name, MUCServer),
  397:     % Create instant room
  398:     Res = create_instant_room(RoomJID, Alice, <<"Ali">>, Config),
  399:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
  400:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)),
  401:     Res2 = list_rooms(MUCServer, Alice, null, null, Config),
  402:     ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))),
  403:     % Delete room
  404:     Res3 = delete_room(RoomJID, null, Config),
  405:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3),
  406:                                           <<"successfully">>)),
  407:     Res4 = list_rooms(MUCServer, Alice, null, null, Config),
  408:     ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))).
  409: 
  410: admin_create_room_with_unprepped_name(Config) ->
  411:     FreshConfig = escalus_fresh:create_users(Config, [{alice, 1}]),
  412:     AliceJid = escalus_users:get_jid(FreshConfig, alice),
  413:     Name = <<$a, (rand_name())/binary>>, % make it start with a letter
  414:     MUCServer = muc_helper:muc_host(),
  415:     RoomJID = jid:make_noprep(unprep(Name), unprep(MUCServer), <<>>),
  416:     Res = create_instant_room(RoomJID, AliceJid, <<"Ali">>, FreshConfig),
  417:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
  418:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)),
  419:     Res2 = list_rooms(MUCServer, AliceJid, null, null, Config),
  420:     ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))).
  421: 
  422: admin_try_create_instant_room_with_nonexistent_domain(Config) ->
  423:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  424:                                     fun admin_try_create_instant_room_with_nonexistent_domain_story/2).
  425: 
  426: admin_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) ->
  427:     Res = create_instant_room(jid:make_bare(rand_name(), <<"unknown">>), Alice, <<"Ali">>, Config),
  428:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  429: 
  430: admin_try_create_instant_room_with_nonexistent_user(Config) ->
  431:     RoomJID = jid:make_bare(rand_name(), muc_helper:muc_host()),
  432:     JID = <<(rand_name())/binary, "@localhost">>,
  433:     Res = create_instant_room(RoomJID, JID, <<"Ali">>, Config),
  434:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  435: 
  436: admin_try_create_instant_room_with_invalid_args(Config) ->
  437:     Config1 = escalus_fresh:create_users(Config, [{alice, 1}]),
  438:     AliceJid = escalus_users:get_jid(Config1, alice),
  439:     AliceDomain = escalus_users:get_host(Config1, alice),
  440:     Domain = muc_helper:muc_host(),
  441:     Res1 = create_instant_room(<<"test room@", Domain/binary>>, AliceJid, <<"Ali">>, Config1),
  442:     assert_coercion_err(Res1, <<"failed_to_parse_jid">>),
  443:     Res2 = create_instant_room(<<"testroom@", Domain/binary, "/res1">>, AliceJid, <<"Ali">>, Config1),
  444:     assert_coercion_err(Res2, <<"jid_with_resource">>),
  445:     Res3 = create_instant_room(Domain, AliceJid, <<"Ali">>, Config1),
  446:     assert_coercion_err(Res3, <<"jid_without_local_part">>),
  447:     Res4 = create_instant_room(<<"testroom@", Domain/binary>>, AliceDomain, <<"Ali">>, Config1),
  448:     assert_coercion_err(Res4, <<"jid_without_local_part">>),
  449:     Res5 = create_instant_room(<<"testroom@", Domain/binary>>, AliceJid, <<>>, Config1),
  450:     assert_coercion_err(Res5, <<"empty_resource_name">>).
  451: 
  452: admin_try_delete_nonexistent_room(Config) ->
  453:     RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()),
  454:     Res = delete_room(RoomJID, null, Config),
  455:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
  456: 
  457: admin_try_delete_room_with_nonexistent_domain(Config) ->
  458:     RoomJID = jid:make_bare(<<"unknown">>, <<"unknown">>),
  459:     Res = delete_room(RoomJID, null, Config),
  460:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
  461: 
  462: admin_invite_user(Config) ->
  463:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_invite_user_story/3).
  464: 
  465: admin_invite_user_story(Config, Alice, Bob) ->
  466:     RoomJIDBin = ?config(room_jid, Config),
  467:     RoomJID = jid:from_binary(RoomJIDBin),
  468:     Res = invite_user(RoomJID, Alice, Bob, null, Config),
  469:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res),
  470:                                           <<"successfully">>)),
  471:     Stanza = escalus:wait_for_stanza(Bob),
  472:     escalus:assert(is_message, Stanza),
  473:     ?assertEqual(RoomJIDBin,
  474:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])),
  475:     ?assertEqual(undefined, exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"password">>}])).
  476: 
  477: admin_invite_user_with_password(Config) ->
  478:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
  479:                                [{alice, 1}, {bob, 1}], fun admin_invite_user_with_password/3).
  480: 
  481: admin_invite_user_with_password(Config, Alice, Bob) ->
  482:     RoomJIDBin = ?config(room_jid, Config),
  483:     RoomJID = jid:from_binary(RoomJIDBin),
  484:     Res = invite_user(RoomJID, Alice, Bob, null, Config),
  485:     assert_success(?INVITE_USER_PATH, Res),
  486:     Stanza = escalus:wait_for_stanza(Bob),
  487:     escalus:assert(is_message, Stanza),
  488:     ?assertEqual(RoomJIDBin,
  489:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])),
  490:     ?assertEqual(?PASSWORD, exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"password">>}])).
  491: 
  492: admin_try_invite_user_to_nonexistent_room(Config) ->
  493:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  494:                                     fun admin_try_invite_user_to_nonexistent_room_story/3).
  495: 
  496: admin_try_invite_user_to_nonexistent_room_story(Config, Alice, Bob) ->
  497:     Res = invite_user(?NONEXISTENT_ROOM, Alice, Bob, null, Config),
  498:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  499: 
  500: admin_kick_user(Config) ->
  501:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_kick_user_story/3).
  502: 
  503: admin_kick_user_story(Config, Alice, Bob) ->
  504:     RoomJIDBin = ?config(room_jid, Config),
  505:     RoomJID = jid:from_binary(RoomJIDBin),
  506:     BobNick = <<"Bobek">>,
  507:     Reason = <<"You are too laud">>,
  508:     enter_room(RoomJID, Alice, <<"ali">>),
  509:     enter_room(RoomJID, Bob, BobNick),
  510:     Res = kick_user(RoomJID, BobNick, Reason, Config),
  511:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res),
  512:                                           <<"successfully">>)),
  513:     escalus:wait_for_stanzas(Bob, 2),
  514:     KickStanza = escalus:wait_for_stanza(Bob),
  515:     escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza),
  516:     ?assertEqual(Reason,
  517:                  exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>},
  518:                                               {element, <<"reason">>}, cdata])).
  519: 
  520: admin_try_kick_user_from_room_without_moderators(Config) ->
  521:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  522:                                fun admin_try_kick_user_from_room_without_moderators/3).
  523: 
  524: admin_try_kick_user_from_room_without_moderators(Config, _Alice, Bob) ->
  525:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  526:     BobNick = <<"Bobek">>,
  527:     enter_room(RoomJID, Bob, BobNick),
  528:     Res = kick_user(RoomJID, BobNick, null, Config),
  529:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  530: 
  531: admin_try_kick_user_from_nonexistent_room(Config) ->
  532:     Res = kick_user(?NONEXISTENT_ROOM, <<"ali">>, null, Config),
  533:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  534: 
  535: admin_send_message_to_room(Config) ->
  536:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  537:                                fun admin_send_message_to_room_story/3).
  538: 
  539: admin_send_message_to_room_story(Config, _Alice, Bob) ->
  540:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  541:     Message = <<"Hello All!">>,
  542:     BobNick = <<"Bobek">>,
  543:     enter_room(RoomJID, Bob, BobNick),
  544:     escalus:wait_for_stanza(Bob),
  545:     % Try send message from bare JID,
  546:     BareBob = escalus_client:short_jid(Bob),
  547:     Res = send_message_to_room(RoomJID, BareBob, Message, Config),
  548:     assert_no_full_jid(Res),
  549:     % Send message
  550:     Res1 = send_message_to_room(RoomJID, Bob, Message, Config),
  551:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res1),
  552:                                           <<"successfully">>)),
  553:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
  554:                               escalus:wait_for_stanza(Bob)).
  555: 
  556: admin_send_private_message(Config) ->
  557:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  558:                                fun admin_send_private_message/3).
  559: 
  560: admin_send_private_message(Config, Alice, Bob) ->
  561:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  562:     Message = <<"Hello Bob!">>,
  563:     BobNick = <<"Bobek">>,
  564:     AliceNick = <<"Ali">>,
  565:     enter_room(RoomJID, Alice, AliceNick),
  566:     enter_room(RoomJID, Bob, BobNick),
  567:     escalus:wait_for_stanzas(Bob, 2),
  568:     % Try send private message from bare JID,
  569:     BareAlice = escalus_client:short_jid(Alice),
  570:     Res = send_private_message(RoomJID, BareAlice, BobNick, Message, Config),
  571:     assert_no_full_jid(Res),
  572:     % Try send private message to empty nick
  573:     Res1 = send_private_message(RoomJID, Alice, <<>>, Message, Config),
  574:     assert_coercion_err(Res1, <<"empty_resource_name">>),
  575:     % Send message
  576:     Res2 = send_private_message(RoomJID, Alice, BobNick, Message, Config),
  577:     assert_success(?SEND_PRIV_MESG_PATH, Res2),
  578:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
  579:                               escalus:wait_for_stanza(Bob)).
  580: 
  581: admin_get_room_config(Config) ->
  582:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_get_room_config_story/2).
  583: 
  584: admin_get_room_config_story(Config, _Alice) ->
  585:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  586:     Res = get_room_config(RoomJID, Config),
  587:     assert_default_room_config(Res).
  588: 
  589: admin_try_get_nonexistent_room_config(Config) ->
  590:     Res = get_room_config(?NONEXISTENT_ROOM, Config),
  591:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  592: 
  593: admin_change_room_config(Config) ->
  594:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_change_room_config_story/2).
  595: 
  596: admin_change_room_config_story(Config, _Alice) ->
  597:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  598:     Title = <<"aloes">>,
  599:     Description = <<"The chat about aloes">>,
  600:     Public = false,
  601:     RoomConfig = #{title => Title, description => Description, public => Public},
  602:     Res = change_room_config(RoomJID, RoomConfig, Config),
  603:     ?assertMatch(#{<<"title">> := Title,
  604:                    <<"description">> := Description,
  605:                    <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)).
  606: 
  607: admin_try_change_nonexistent_room_config(Config) ->
  608:     RoomConfig = #{title => <<"NewTitle">>},
  609:     Res = change_room_config(?NONEXISTENT_ROOM, RoomConfig, Config),
  610:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  611: 
  612: admin_list_room_users(Config) ->
  613:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  614:                                fun admin_list_room_users_story/3).
  615: 
  616: admin_list_room_users_story(Config, Alice, Bob) ->
  617:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  618:     BobNick = <<"Bobek">>,
  619:     AliceNick = <<"Ali">>,
  620:     enter_room(RoomJID, Bob, BobNick),
  621:     enter_room(RoomJID, Alice, AliceNick),
  622:     Res = list_room_users(RoomJID, Config),
  623:     ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>},
  624:                      {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}],
  625:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
  626: 
  627: admin_try_list_users_from_nonexistent_room(Config) ->
  628:     Res = list_room_users(?NONEXISTENT_ROOM, Config),
  629:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  630: 
  631: admin_get_room_messages(Config) ->
  632:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  633:                                fun admin_get_room_messages_story/3).
  634: 
  635: admin_get_room_messages_story(Config, Alice, Bob) ->
  636:     RoomJID = #jid{luser = RoomName, lserver = MUCDomain} =
  637:         jid:from_binary(?config(room_jid, Config)),
  638:     enter_room(RoomJID, Bob, <<"Bobek">>),
  639:     enter_room(RoomJID, Alice, <<"Ali">>),
  640:     escalus:wait_for_stanzas(Bob, 2),
  641:     send_message_to_room(RoomJID, Bob, <<"Hi!">>, Config),
  642:     escalus:wait_for_stanzas(Bob, 1),
  643:     mam_helper:wait_for_room_archive_size(MUCDomain, RoomName, 1),
  644:     Res = get_room_messages(RoomJID, 50, null, Config),
  645:     #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} =
  646:         get_ok_value(?GET_MESSAGES_PATH, Res),
  647:     ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)).
  648: 
  649: admin_try_get_nonexistent_room_messages(Config) ->
  650:     Res = get_room_messages(?NONEXISTENT_ROOM, null, null, Config),
  651:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  652: 
  653: 
  654: admin_set_user_affiliation(Config) ->
  655:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  656:                                fun admin_set_user_affiliation/3).
  657: 
  658: admin_set_user_affiliation(Config, _Alice, Bob) ->
  659:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  660:     % Grant member affiliation
  661:     Res = set_user_affiliation(RoomJID, Bob, member, Config),
  662:     assert_success(?SET_AFFILIATION_PATH, Res),
  663:     assert_user_affiliation(RoomJID, Bob, member),
  664:     % Grant admin affiliation
  665:     Res1 = set_user_affiliation(RoomJID, Bob, admin, Config),
  666:     assert_success(?SET_AFFILIATION_PATH, Res1),
  667:     assert_user_affiliation(RoomJID, Bob, admin),
  668:     % Grant owner affiliation
  669:     Res2 = set_user_affiliation(RoomJID, Bob, owner, Config),
  670:     assert_success(?SET_AFFILIATION_PATH, Res2),
  671:     assert_user_affiliation(RoomJID, Bob, owner),
  672:     % Revoke affiliation
  673:     Res3 = set_user_affiliation(RoomJID, Bob, none, Config),
  674:     assert_success(?SET_AFFILIATION_PATH, Res3),
  675:     assert_user_affiliation(RoomJID, Bob, none),
  676:     % Ban user
  677:     Res4 = set_user_affiliation(RoomJID, Bob, outcast, Config),
  678:     assert_success(?SET_AFFILIATION_PATH, Res4),
  679:     assert_user_affiliation(RoomJID, Bob, outcast).
  680: 
  681: admin_try_set_nonexistent_room_user_affiliation(Config) ->
  682:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  683:                                     fun admin_try_set_nonexistent_room_user_affiliation/2).
  684: 
  685: admin_try_set_nonexistent_room_user_affiliation(Config, Alice) ->
  686:     Res = set_user_affiliation(?NONEXISTENT_ROOM, Alice, admin, Config),
  687:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  688: 
  689: admin_set_user_role(Config) ->
  690:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_set_user_role/3).
  691: 
  692: admin_set_user_role(Config, Alice, Bob) ->
  693:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  694:     BobNick = <<"Boobek">>,
  695:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
  696:     enter_room(RoomJID, Bob, BobNick),
  697:     % Change from participant to visitor
  698:     Res = set_user_role(RoomJID, BobNick, visitor, Config),
  699:     assert_success(?SET_ROLE_PATH, Res),
  700:     assert_user_role(RoomJID, Bob, visitor),
  701:     % Change from visitor to participant
  702:     Res1 = set_user_role(RoomJID, BobNick, participant, Config),
  703:     assert_success(?SET_ROLE_PATH, Res1),
  704:     assert_user_role(RoomJID, Bob, participant),
  705:     % Change from participant to moderator
  706:     Res2 = set_user_role(RoomJID, BobNick, moderator, Config),
  707:     assert_success(?SET_ROLE_PATH, Res2),
  708:     assert_user_role(RoomJID, Bob, moderator).
  709: 
  710: admin_try_set_nonexistent_nick_role(Config) ->
  711:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_try_set_nonexistent_nick_role/2).
  712: 
  713: admin_try_set_nonexistent_nick_role(Config, Alice) ->
  714:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  715:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
  716:     Res = set_user_role(RoomJID, <<"kik">>, visitor, Config),
  717:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)).
  718: 
  719: admin_try_set_user_role_in_room_without_moderators(Config) ->
  720:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  721:                                fun admin_try_set_user_role_in_room_without_moderators/3).
  722: 
  723: admin_try_set_user_role_in_room_without_moderators(Config, _Alice, Bob) ->
  724:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  725:     BobNick = <<"Boobek">>,
  726:     enter_room(RoomJID, Bob, BobNick),
  727:     Res = set_user_role(RoomJID, BobNick, visitor, Config),
  728:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  729: 
  730: admin_try_set_nonexistent_room_user_role(Config) ->
  731:     Res = set_user_role(?NONEXISTENT_ROOM, <<"Alice">>, moderator, Config),
  732:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  733: 
  734: admin_make_user_enter_room(Config) ->
  735:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_enter_room/2).
  736: 
  737: admin_make_user_enter_room(Config, Alice) ->
  738:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  739:     Nick = <<"ali">>,
  740:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
  741:     % Alice enter room with password
  742:     Res = enter_room(RoomJID, Alice, Nick, null, Config),
  743:     assert_success(?ENTER_ROOM_PATH, Res),
  744:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)).
  745: 
  746: admin_make_user_enter_room_with_password(Config) ->
  747:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
  748:                                [{alice, 1}, {bob, 1}],
  749:                                fun admin_make_user_enter_room_with_password/3).
  750: 
  751: admin_make_user_enter_room_with_password(Config, Alice, Bob) ->
  752:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  753:     Nick = <<"ali">>,
  754:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
  755:     % Alice enter room with password
  756:     Res = enter_room(RoomJID, Alice, Nick, ?PASSWORD, Config),
  757:     assert_success(?ENTER_ROOM_PATH, Res),
  758:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)),
  759:     % Bob try enter room without password
  760:     Res1 = enter_room(RoomJID, Bob, <<"Bobek">>, null, Config),
  761:     assert_success(?ENTER_ROOM_PATH, Res1),
  762:     ?assertMatch([_], get_room_users(RoomJID)),
  763:     % Bob enter room with password
  764:     Res2 = enter_room(RoomJID, Bob, <<"Bobek">>, ?PASSWORD, Config),
  765:     assert_success(?ENTER_ROOM_PATH, Res2),
  766:     ?assertMatch([_, _], get_room_users(RoomJID)).
  767: 
  768: admin_make_user_enter_room_bare_jid(Config) ->
  769:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_enter_room_bare_jid/2).
  770: 
  771: admin_make_user_enter_room_bare_jid(Config, Alice) ->
  772:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  773:     BareAlice = escalus_client:short_jid(Alice),
  774:     Res = enter_room(RoomJID, BareAlice, <<"Ali">>, null, Config),
  775:     assert_no_full_jid(Res).
  776: 
  777: admin_make_user_exit_room(Config) ->
  778:     muc_helper:story_with_room(Config, [{persistent, true}], [{alice, 1}],
  779:                                fun admin_make_user_exit_room/2).
  780: 
  781: admin_make_user_exit_room(Config, Alice) ->
  782:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  783:     Nick = <<"ali">>,
  784:     enter_room(RoomJID, Alice, Nick),
  785:     ?assertMatch([_], get_room_users(RoomJID)),
  786:     Res = exit_room(RoomJID, Alice, Nick, Config),
  787:     assert_success(?EXIT_ROOM_PATH, Res),
  788:     ?assertMatch([], get_room_users(RoomJID)).
  789: 
  790: admin_make_user_exit_room_bare_jid(Config) ->
  791:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_make_user_exit_room_bare_jid/2).
  792: 
  793: admin_make_user_exit_room_bare_jid(Config, Alice) ->
  794:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  795:     BareAlice = escalus_client:short_jid(Alice),
  796:     Nick = <<"ali">>,
  797:     enter_room(RoomJID, Alice, Nick),
  798:     Res = exit_room(RoomJID, BareAlice, Nick, Config),
  799:     assert_no_full_jid(Res).
  800: 
  801: admin_list_room_affiliations(Config) ->
  802:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
  803:                                fun admin_list_room_affiliations/3).
  804: 
  805: admin_list_room_affiliations(Config, Alice, Bob) ->
  806:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  807:     BobNick = <<"Bobek">>,
  808:     AliceNick = <<"Ali">>,
  809:     enter_room(RoomJID, Bob, BobNick),
  810:     enter_room(RoomJID, Alice, AliceNick),
  811:     AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  812:     BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  813:     % List all owners
  814:     Res = list_room_affiliations(RoomJID, owner, Config),
  815:     ?assertMatch([#{<<"jid">> := AliceJID, <<"affiliation">> := <<"OWNER">>}],
  816:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res)),
  817:     % List all members
  818:     set_user_affiliation(RoomJID, Bob, member, Config),
  819:     Res1 = list_room_affiliations(RoomJID, member, Config),
  820:     ?assertMatch([#{<<"jid">> := BobJID, <<"affiliation">> := <<"MEMBER">>}],
  821:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res1)),
  822:     % List all
  823:     Res2 = list_room_affiliations(RoomJID, null, Config),
  824:     ?assertMatch([_, _], get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res2)).
  825: 
  826: admin_try_list_nonexistent_room_affiliations(Config) ->
  827:     Res = list_room_affiliations(?NONEXISTENT_ROOM, null, Config),
  828:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
  829: 
  830: %% Admin MUC not configured test cases
  831: 
  832: admin_delete_room_muc_not_configured(Config) ->
  833:     Res = delete_room(get_room_name(), null, Config),
  834:     get_not_loaded(Res).
  835: 
  836: admin_list_room_users_muc_not_configured(Config) ->
  837:     Res = list_room_users(get_room_name(), Config),
  838:     get_not_loaded(Res).
  839: 
  840: admin_change_room_config_muc_not_configured(Config) ->
  841:     RoomConfig = #{title => <<"NewTitle">>},
  842:     Res = change_room_config(get_room_name(), RoomConfig, Config),
  843:     get_not_loaded(Res).
  844: 
  845: admin_get_room_config_muc_not_configured(Config) ->
  846:     Res = get_room_config(get_room_name(), Config),
  847:     get_not_loaded(Res).
  848: 
  849: admin_invite_user_muc_not_configured(Config) ->
  850:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  851:         fun admin_invite_user_muc_not_configured_story/3).
  852: 
  853: admin_invite_user_muc_not_configured_story(Config, Alice, Bob) ->
  854:     Res = invite_user(get_room_name(), Alice, Bob, null, Config),
  855:     get_not_loaded(Res).
  856: 
  857: admin_kick_user_muc_not_configured(Config) ->
  858:     Res = kick_user(get_room_name(), <<"nick">>, <<"reason">>, Config),
  859:     get_not_loaded(Res).
  860: 
  861: admin_send_message_to_room_muc_not_configured(Config) ->
  862:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  863:         fun admin_send_message_to_room_muc_not_configured_story/2).
  864: 
  865: admin_send_message_to_room_muc_not_configured_story(Config, Alice) ->
  866:     Res = send_message_to_room(get_room_name(), Alice, <<"body">>, Config),
  867:     get_not_loaded(Res).
  868: 
  869: admin_send_private_message_muc_not_configured(Config) ->
  870:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  871:         fun admin_send_private_message_muc_not_configured_story/2).
  872: 
  873: admin_send_private_message_muc_not_configured_story(Config, Alice) ->
  874:     Nick = <<"ali">>,
  875:     Res = send_private_message(get_room_name(), Alice, Nick, <<"body">>, Config),
  876:     get_not_loaded(Res).
  877: 
  878: admin_get_room_messages_muc_or_mam_not_configured(Config) ->
  879:     Res = get_room_messages(get_room_name(), 4, null, Config),
  880:     get_not_loaded(Res).
  881: 
  882: admin_set_user_affiliation_muc_not_configured(Config) ->
  883:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  884:         fun admin_set_user_affiliation_muc_not_configured_story/2).
  885: 
  886: admin_set_user_affiliation_muc_not_configured_story(Config, Alice) ->
  887:     Res = set_user_affiliation(get_room_name(), Alice, member, Config),
  888:     get_not_loaded(Res).
  889: 
  890: admin_set_user_role_muc_not_configured(Config) ->
  891:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  892:         fun admin_set_user_role_muc_not_configured_story/2).
  893: 
  894: admin_set_user_role_muc_not_configured_story(Config, Alice) ->
  895:     Res = set_user_role(get_room_name(), Alice, moderator, Config),
  896:     get_not_loaded(Res).
  897: 
  898: admin_make_user_enter_room_muc_not_configured(Config) ->
  899:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  900:         fun admin_make_user_enter_room_muc_light_not_configured_story/2).
  901: 
  902: admin_make_user_enter_room_muc_light_not_configured_story(Config, Alice) ->
  903:     Nick = <<"ali">>,
  904:     Res = enter_room(get_room_name(), Alice, Nick, null, Config),
  905:     get_not_loaded(Res).
  906: 
  907: admin_make_user_exit_room_muc_not_configured(Config) ->
  908:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  909:         fun admin_make_user_exit_room_muc_not_configured_story/2).
  910: 
  911: admin_make_user_exit_room_muc_not_configured_story(Config, Alice) ->
  912:     Nick = <<"ali">>,
  913:     Res = exit_room(get_room_name(), Alice, Nick, Config),
  914:     get_not_loaded(Res).
  915: 
  916: admin_list_room_affiliations_muc_not_configured(Config) ->
  917:     Res = list_room_affiliations(get_room_name(), member, Config),
  918:     get_not_loaded(Res).
  919: 
  920: %% Domain admin test cases
  921: 
  922: domain_admin_try_delete_room_with_nonexistent_domain(Config) ->
  923:     RoomJID = jid:make_bare(<<"unknown">>, <<"unknown">>),
  924:     get_unauthorized(delete_room(RoomJID, null, Config)).
  925: 
  926: domain_admin_create_and_delete_room_no_permission(Config) ->
  927:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  928:                                     fun domain_admin_create_and_delete_room_no_permission_story/2).
  929: 
  930: domain_admin_create_and_delete_room_no_permission_story(Config, AliceBis) ->
  931:     ExternalDomain = domain_helper:secondary_domain(),
  932:     UnknownDomain = <<"unknown">>,
  933:     RoomJid = jid:make_bare(rand_name(), muc_helper:muc_host()),
  934:     ExternalServer = <<"muc.", ExternalDomain/binary>>,
  935:     % Create instant room with a non-existent domain
  936:     UnknownJID = <<(rand_name())/binary, "@", UnknownDomain/binary>>,
  937:     Res = create_instant_room(RoomJid, UnknownJID, <<"Ali">>, Config),
  938:     get_unauthorized(Res),
  939:     % Create instant room with an external domain
  940:     Res2 = create_instant_room(RoomJid, AliceBis, <<"Ali">>, Config),
  941:     get_unauthorized(Res2),
  942:     % Delete instant room with a non-existent domain
  943:     UnknownRoomJID = jid:make_bare(<<"unknown_room">>, UnknownDomain),
  944:     Res3 = delete_room(UnknownRoomJID, null, Config),
  945:     get_unauthorized(Res3),
  946:     % Delete instant room with an external domain
  947:     ExternalRoomJID = jid:make_bare(<<"external_room">>, ExternalServer),
  948:     Res4 = delete_room(ExternalRoomJID, null, Config),
  949:     get_unauthorized(Res4).
  950: 
  951: domain_admin_list_rooms_no_permission(Config) ->
  952:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  953:                                     fun domain_admin_list_rooms_no_permission_story/2).
  954: 
  955: domain_admin_list_rooms_no_permission_story(Config, AliceBis) ->
  956:     AliceBisJID = jid:from_binary(escalus_client:short_jid(AliceBis)),
  957:     AliceBisRoom = rand_name(),
  958:     muc_helper:create_instant_room(AliceBisRoom, AliceBisJID, <<"Ali">>, []),
  959:     Res = list_rooms(muc_helper:muc_host(), AliceBis, null, null, Config),
  960:     get_unauthorized(Res).
  961: 
  962: domain_admin_list_room_users_no_permission(Config) ->
  963:     get_unauthorized(list_room_users(?NONEXISTENT_ROOM, Config)),
  964:     get_unauthorized(list_room_users(?EXTERNAL_DOMAIN_ROOM, Config)).
  965: 
  966: domain_admin_change_room_config_no_permission(Config) ->
  967:     RoomConfig = #{title => <<"NewTitle">>},
  968:     get_unauthorized(change_room_config(?NONEXISTENT_ROOM, RoomConfig, Config)),
  969:     get_unauthorized(change_room_config(?EXTERNAL_DOMAIN_ROOM, RoomConfig, Config)).
  970: 
  971: domain_admin_get_room_config_no_permission(Config) ->
  972:     get_unauthorized(get_room_config(?NONEXISTENT_ROOM, Config)),
  973:     get_unauthorized(get_room_config(?EXTERNAL_DOMAIN_ROOM, Config)).
  974: 
  975: domain_admin_invite_user_no_permission(Config) ->
  976:     muc_helper:story_with_room(Config, [], [{alice_bis, 1}, {bob, 1}],
  977:                                fun domain_admin_invite_user_no_permission_story/3).
  978: 
  979: domain_admin_invite_user_no_permission_story(Config, Alice, Bob) ->
  980:     RoomJIDBin = ?config(room_jid, Config),
  981:     RoomJID = jid:from_binary(RoomJIDBin),
  982:     Res = invite_user(RoomJID, Alice, Bob, null, Config),
  983:     get_unauthorized(Res).
  984: 
  985: domain_admin_kick_user_no_permission(Config) ->
  986:     get_unauthorized(kick_user(?NONEXISTENT_ROOM, <<"ali">>, null, Config)),
  987:     get_unauthorized(kick_user(?EXTERNAL_DOMAIN_ROOM, <<"ali">>, null, Config)).
  988: 
  989: domain_admin_send_message_to_room_no_permission(Config) ->
  990:     muc_helper:story_with_room(Config, [], [{alice_bis, 1}],
  991:                                 fun domain_admin_send_message_to_room_no_permission_story/2).
  992: 
  993: domain_admin_send_message_to_room_no_permission_story(Config, AliceBis) ->
  994:     RoomJID = jid:from_binary(?config(room_jid, Config)),
  995:     Message = <<"Hello All!">>,
  996:     AliceNick = <<"Bobek">>,
  997:     enter_room(RoomJID, AliceBis, AliceNick),
  998:     escalus:wait_for_stanza(AliceBis),
  999:     % Send message
 1000:     Res = send_message_to_room(RoomJID, AliceBis, Message, Config),
 1001:     get_unauthorized(Res).
 1002: 
 1003: domain_admin_send_private_message_no_permission(Config) ->
 1004:     muc_helper:story_with_room(Config, [], [{alice_bis, 1}, {bob, 1}],
 1005:                                fun domain_admin_send_private_message_no_permission_story/3).
 1006: 
 1007: domain_admin_send_private_message_no_permission_story(Config, AliceBis, Bob) ->
 1008:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1009:     Message = <<"Hello Bob!">>,
 1010:     BobNick = <<"Bobek">>,
 1011:     AliceBisNick = <<"Ali">>,
 1012:     enter_room(RoomJID, AliceBis, AliceBisNick),
 1013:     enter_room(RoomJID, Bob, BobNick),
 1014:     escalus:wait_for_stanzas(Bob, 2),
 1015:     % Send message
 1016:     Res = send_private_message(RoomJID, AliceBis, BobNick, Message, Config),
 1017:     get_unauthorized(Res).
 1018: 
 1019: domain_admin_get_room_messages_no_permission(Config) ->
 1020:     get_unauthorized(get_room_messages(?NONEXISTENT_ROOM, null, null, Config)),
 1021:     get_unauthorized(get_room_messages(?EXTERNAL_DOMAIN_ROOM, null, null, Config)).
 1022: 
 1023: domain_admin_set_user_affiliation_no_permission(Config) ->
 1024:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1025:                                     fun domain_admin_set_user_affiliation_no_permission_story/2).
 1026: 
 1027: domain_admin_set_user_affiliation_no_permission_story(Config, Alice) ->
 1028:     get_unauthorized(set_user_affiliation(?NONEXISTENT_ROOM, Alice, admin, Config)),
 1029:     get_unauthorized(set_user_affiliation(?EXTERNAL_DOMAIN_ROOM, Alice, admin, Config)).
 1030: 
 1031: domain_admin_set_user_role_no_permission(Config) ->
 1032:     get_unauthorized(set_user_role(?NONEXISTENT_ROOM, <<"Alice">>, moderator, Config)),
 1033:     get_unauthorized(set_user_role(?EXTERNAL_DOMAIN_ROOM, <<"Alice">>, moderator, Config)).
 1034: 
 1035: domain_admin_list_room_affiliations_no_permission(Config) ->
 1036:     get_unauthorized(list_room_affiliations(?NONEXISTENT_ROOM, null, Config)),
 1037:     get_unauthorized(list_room_affiliations(?EXTERNAL_DOMAIN_ROOM, null, Config)).
 1038: 
 1039: domain_admin_make_user_enter_room_no_permission(Config) ->
 1040:     muc_helper:story_with_room(Config, [], [{alice_bis, 1}],
 1041:                                fun domain_admin_make_user_enter_room_no_permission_story/2).
 1042: 
 1043: domain_admin_make_user_enter_room_no_permission_story(Config, AliceBis) ->
 1044:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1045:     Nick = <<"ali">>,
 1046:     % Enter room without password
 1047:     Res = enter_room(RoomJID, AliceBis, Nick, null, Config),
 1048:     get_unauthorized(Res),
 1049:     % Enter room with password
 1050:     Res2 = enter_room(RoomJID, AliceBis, Nick, ?PASSWORD, Config),
 1051:     get_unauthorized(Res2).
 1052: 
 1053: domain_admin_make_user_exit_room_no_permission(Config) ->
 1054:     muc_helper:story_with_room(Config, [{persistent, true}], [{alice_bis, 1}],
 1055:                                fun domain_admin_make_user_exit_room_no_permission_story/2).
 1056: 
 1057: domain_admin_make_user_exit_room_no_permission_story(Config, AliceBis) ->
 1058:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1059:     Nick = <<"ali">>,
 1060:     enter_room(RoomJID, AliceBis, Nick),
 1061:     ?assertMatch([_], get_room_users(RoomJID)),
 1062:     Res = exit_room(RoomJID, AliceBis, Nick, Config),
 1063:     get_unauthorized(Res).
 1064: 
 1065: %% User test cases
 1066: 
 1067: user_list_rooms(Config) ->
 1068:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun user_list_rooms_story/3).
 1069: 
 1070: user_list_rooms_story(Config, Alice, Bob) ->
 1071:     AliceJID = jid:from_binary(escalus_client:short_jid(Alice)),
 1072:     BobJID = jid:from_binary(escalus_client:short_jid(Bob)),
 1073:     AliceRoom = rand_name(),
 1074:     BobRoom = rand_name(),
 1075:     muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []),
 1076:     muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, []),
 1077: 
 1078:     Res = user_list_rooms(Alice, muc_helper:muc_host(), null, null, Config),
 1079:     #{<<"rooms">> := Rooms } = get_ok_value(?LIST_ROOMS_PATH, Res),
 1080:     ?assert(contain_room(AliceRoom, Rooms)),
 1081:     ?assert(contain_room(BobRoom, Rooms)).
 1082: 
 1083: user_try_list_rooms_for_nonexistent_domain(Config) ->
 1084:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1085:                                     fun user_try_list_rooms_for_nonexistent_domain_story/2).
 1086: 
 1087: user_try_list_rooms_for_nonexistent_domain_story(Config, Alice) ->
 1088:     Res1 = user_list_rooms(Alice, <<"baddomain">>, null, null, Config),
 1089:     ?assertMatch({_, _}, binary:match(get_err_msg(Res1), <<"not found">>)),
 1090:     %% Domain instead of the MUC subdomain
 1091:     Res2 = user_list_rooms(Alice, domain_helper:domain(), null, null, Config),
 1092:     ?assertMatch({_, _}, binary:match(get_err_msg(Res2), <<"not found">>)).
 1093: 
 1094: user_create_and_delete_room(Config) ->
 1095:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_create_and_delete_room_story/2).
 1096: 
 1097: user_create_and_delete_room_story(Config, Alice) ->
 1098:     Name = rand_name(),
 1099:     MUCServer = muc_helper:muc_host(),
 1100:     RoomJID = jid:make_bare(Name, MUCServer),
 1101:     % Create instant room
 1102:     Res = user_create_instant_room(Alice, RoomJID, <<"Ali">>, Config),
 1103:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
 1104:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)),
 1105:     Res2 = user_list_rooms(Alice, MUCServer, null, null, Config),
 1106:     ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))),
 1107:     % Delete room
 1108:     Res3 = user_delete_room(Alice, RoomJID, null, Config),
 1109:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3),
 1110:                                           <<"successfully">>)),
 1111:     Res4 = user_list_rooms(Alice, MUCServer, null, null, Config),
 1112:     ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))).
 1113: 
 1114: user_create_room_with_unprepped_name(Config) ->
 1115:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1116:                                     fun user_create_room_with_unprepped_name_story/2).
 1117: 
 1118: user_create_room_with_unprepped_name_story(Config, Alice) ->
 1119:     Name = <<$a, (rand_name())/binary>>, % make it start with a letter
 1120:     MUCServer = muc_helper:muc_host(),
 1121:     RoomJid = jid:make_noprep(unprep(Name), unprep(MUCServer), <<>>),
 1122:     Res = user_create_instant_room(Alice, RoomJid, <<"Ali">>, Config),
 1123:     ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0},
 1124:                  get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)).
 1125: 
 1126: user_try_create_instant_room_with_nonexistent_domain(Config) ->
 1127:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1128:                                     fun user_try_create_instant_room_with_nonexistent_domain_story/2).
 1129: 
 1130: user_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) ->
 1131:     RoomJID = jid:make_bare(rand_name(), <<"unknown">>),
 1132:     Res = user_create_instant_room(Alice, RoomJID, <<"Ali">>, Config),
 1133:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1134: 
 1135: user_try_create_instant_room_with_invalid_args(Config) ->
 1136:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1137:                                     fun user_try_create_instant_room_with_invalid_args_story/2).
 1138: 
 1139: user_try_create_instant_room_with_invalid_args_story(Config, Alice) ->
 1140:     Domain = muc_helper:muc_host(),
 1141:     Res1 = user_create_instant_room(Alice, <<"test room@", Domain/binary>>, <<"Ali">>, Config),
 1142:     assert_coercion_err(Res1, <<"failed_to_parse_jid">>),
 1143:     Res2 = user_create_instant_room(Alice, <<"testroom@", Domain/binary, "/res1">>, <<"Ali">>, Config),
 1144:     assert_coercion_err(Res2, <<"jid_with_resource">>),
 1145:     Res3 = user_create_instant_room(Alice, <<"testroom@", Domain/binary>>, <<>>, Config),
 1146:     assert_coercion_err(Res3, <<"empty_resource_name">>).
 1147: 
 1148: user_try_delete_nonexistent_room(Config) ->
 1149:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1150:                                     fun user_try_delete_nonexistent_room_story/2).
 1151: 
 1152: user_try_delete_nonexistent_room_story(Config, Alice) ->
 1153:     RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()),
 1154:     Res = user_delete_room(Alice, RoomJID, null, Config),
 1155:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)).
 1156: 
 1157: user_try_delete_room_by_not_owner(Config) ->
 1158:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1159:                                fun user_try_delete_room_by_not_owner_story/3).
 1160: 
 1161: user_try_delete_room_by_not_owner_story(Config, _Alice, Bob) ->
 1162:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1163:     Res = user_delete_room(Bob, RoomJID, null, Config),
 1164:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
 1165: 
 1166: user_invite_user(Config) ->
 1167:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_invite_user_story/3).
 1168: 
 1169: user_invite_user_story(Config, Alice, Bob) ->
 1170:     RoomJIDBin = ?config(room_jid, Config),
 1171:     RoomJID = jid:from_binary(RoomJIDBin),
 1172:     Res = user_invite_user(Alice, RoomJID, Bob, null, Config),
 1173:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res),
 1174:                                           <<"successfully">>)),
 1175:     Stanza = escalus:wait_for_stanza(Bob),
 1176:     escalus:assert(is_message, Stanza),
 1177:     ?assertEqual(RoomJIDBin,
 1178:                  exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])).
 1179: 
 1180: user_kick_user(Config) ->
 1181:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_kick_user_story/3).
 1182: 
 1183: user_kick_user_story(Config, Alice, Bob) ->
 1184:     RoomJIDBin = ?config(room_jid, Config),
 1185:     RoomJID = jid:from_binary(RoomJIDBin),
 1186:     BobNick = <<"Bobek">>,
 1187:     Reason = <<"You are too loud">>,
 1188:     enter_room(RoomJID, Alice, <<"ali">>),
 1189:     enter_room(RoomJID, Bob, BobNick),
 1190:     Res = user_kick_user(Alice, RoomJID, BobNick, Reason, Config),
 1191:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res),
 1192:                                           <<"successfully">>)),
 1193:     escalus:wait_for_stanzas(Bob, 2),
 1194:     KickStanza = escalus:wait_for_stanza(Bob),
 1195:     escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza),
 1196:     ?assertEqual(Reason,
 1197:                  exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>},
 1198:                                               {element, <<"reason">>}, cdata])).
 1199: 
 1200: user_try_kick_user_without_moderator_resource(Config) ->
 1201:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1202:                                fun user_try_kick_user_without_moderator_resource/3).
 1203: 
 1204: user_try_kick_user_without_moderator_resource(Config, Alice, Bob) ->
 1205:     RoomJIDBin = ?config(room_jid, Config),
 1206:     RoomJID = jid:from_binary(RoomJIDBin),
 1207:     BobNick = <<"Bobek">>,
 1208:     enter_room(RoomJID, Bob, BobNick),
 1209:     Res = user_kick_user(Alice, RoomJID, BobNick, null, Config),
 1210:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1211: 
 1212: user_try_kick_user_from_nonexistent_room(Config) ->
 1213:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1214:                                     fun user_try_kick_user_from_nonexistent_room/2).
 1215: 
 1216: user_try_kick_user_from_nonexistent_room(Config, Alice) ->
 1217:     Res = user_kick_user(Alice, ?NONEXISTENT_ROOM, <<"bobi">>, null, Config),
 1218:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1219: 
 1220: user_send_message_to_room(Config) ->
 1221:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1222:                                fun user_send_message_to_room_story/3).
 1223: 
 1224: user_send_message_to_room_story(Config, _Alice, Bob) ->
 1225:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1226:     Message = <<"Hello All!">>,
 1227:     BobNick = <<"Bobek">>,
 1228:     enter_room(RoomJID, Bob, BobNick),
 1229:     escalus:wait_for_stanza(Bob),
 1230:     % Send message
 1231:     Res = user_send_message_to_room(Bob, RoomJID, Message, null, Config),
 1232:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res),
 1233:                                           <<"successfully">>)),
 1234:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
 1235:                               escalus:wait_for_stanza(Bob)).
 1236: 
 1237: user_send_message_to_room_with_specified_res(Config) ->
 1238:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 2}],
 1239:                                fun user_send_message_to_room_with_specified_res_story/4).
 1240: 
 1241: user_send_message_to_room_with_specified_res_story(Config, _Alice, Bob, Bob2) ->
 1242:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1243:     Message = <<"Hello All!">>,
 1244:     BobNick = <<"Bobek">>,
 1245:     enter_room(RoomJID, Bob2, BobNick),
 1246:     escalus:wait_for_stanza(Bob2),
 1247:     % Send message, the resource should be normalized to "res2"
 1248:     Res = user_send_message_to_room(Bob, RoomJID, Message, <<"res₂"/utf8>>, Config),
 1249:     ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res),
 1250:                                           <<"successfully">>)),
 1251:     assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message,
 1252:                               escalus:wait_for_stanza(Bob2)).
 1253: 
 1254: user_send_private_message(Config) ->
 1255:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1256:                                fun user_send_private_message/3).
 1257: 
 1258: user_send_private_message(Config, Alice, Bob) ->
 1259:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1260:     Message = <<"Hello Bob!">>,
 1261:     BobNick = <<"Bobek">>,
 1262:     AliceNick = <<"Ali">>,
 1263:     enter_room(RoomJID, Bob, BobNick),
 1264:     enter_room(RoomJID, Alice, AliceNick),
 1265:     escalus:wait_for_stanzas(Bob, 2),
 1266:     % Send message
 1267:     Res = user_send_private_message(Alice, RoomJID, Message, BobNick, null, Config),
 1268:     assert_success(?SEND_PRIV_MESG_PATH, Res),
 1269:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
 1270:                               escalus:wait_for_stanza(Bob)).
 1271: 
 1272: user_send_private_message_with_specified_res(Config) ->
 1273:     muc_helper:story_with_room(Config, [], [{alice, 2}, {bob, 1}],
 1274:                                fun user_send_private_message/3).
 1275: 
 1276: user_send_private_message_with_specified_res(Config, Alice, Alice2, Bob) ->
 1277:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1278:     Message = <<"Hello Bob!">>,
 1279:     BobNick = <<"Bobek">>,
 1280:     AliceNick = <<"Ali">>,
 1281:     enter_room(RoomJID, Bob, BobNick),
 1282:     enter_room(RoomJID, Alice2, AliceNick),
 1283:     escalus:wait_for_stanzas(Bob, 2),
 1284:     % Send message, the resource should be normalized to "res2"
 1285:     Res = user_send_private_message(Alice, RoomJID, Message, BobNick, <<"res₂"/utf8>>, Config),
 1286:     assert_success(?SEND_PRIV_MESG_PATH, Res),
 1287:     assert_is_message_correct(RoomJID, AliceNick, <<"chat">>, Message,
 1288:                               escalus:wait_for_stanza(Bob)).
 1289: 
 1290: user_without_session_send_message_to_room(Config) ->
 1291:     muc_helper:story_with_room(Config, [], [{alice, 1}],
 1292:                                fun user_without_session_send_message_to_room_story/2).
 1293: 
 1294: user_without_session_send_message_to_room_story(Config, Alice) ->
 1295:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1296:     JID = jid:from_binary(escalus_client:full_jid(Alice)),
 1297:     terminate_user_session(JID),
 1298:     % Send message
 1299:     Res = user_send_message_to_room(Alice, RoomJID, <<"Hello!">>, null, Config),
 1300:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have any session">>)).
 1301: 
 1302: terminate_user_session(Jid) ->
 1303:     ?assertEqual(ok, rpc(mim(), ejabberd_sm, terminate_session, [Jid, <<"Kicked">>])),
 1304:     F = fun() -> rpc(mim(), ejabberd_sm, get_user_resources, [Jid]) end,
 1305:     mongoose_helper:wait_until(F, [], #{time_left => timer:seconds(5)}).
 1306: 
 1307: user_get_room_config(Config) ->
 1308:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1309:                                fun user_get_room_config_story/3).
 1310: 
 1311: user_get_room_config_story(Config, Alice, Bob) ->
 1312:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1313:     Res = user_get_room_config(Alice, RoomJID, Config),
 1314:     assert_default_room_config(Res),
 1315:     % Not an owner tries to get room config
 1316:     Res2 = user_get_room_config(Bob, RoomJID, Config),
 1317:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)).
 1318: 
 1319: user_try_get_nonexistent_room_config(Config) ->
 1320:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1321:                                     fun user_try_get_nonexistent_room_config_story/2).
 1322: 
 1323: user_try_get_nonexistent_room_config_story(Config, Alice) ->
 1324:     Res = user_get_room_config(Alice, ?NONEXISTENT_ROOM, Config),
 1325:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1326: 
 1327: user_change_room_config(Config) ->
 1328:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1329:                                fun user_change_room_config_story/3).
 1330: 
 1331: user_change_room_config_story(Config, Alice, Bob) ->
 1332:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1333:     Title = <<"aloes">>,
 1334:     Description = <<"The chat about aloes">>,
 1335:     Public = false,
 1336:     RoomConfig = #{title => Title, description => Description, public => Public},
 1337:     Res = user_change_room_config(Alice, RoomJID, RoomConfig, Config),
 1338:     ?assertMatch(#{<<"title">> := Title,
 1339:                    <<"description">> := Description,
 1340:                    <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)),
 1341:     % Not an owner tries to change the room config
 1342:     Res2 = user_change_room_config(Bob, RoomJID, RoomConfig, Config),
 1343:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)).
 1344: 
 1345: user_try_change_nonexistent_room_config(Config) ->
 1346:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1347:                                     fun user_try_change_nonexistent_room_config_story/2).
 1348: 
 1349: user_try_change_nonexistent_room_config_story(Config, Alice) ->
 1350:     RoomConfig = #{title => <<"NewTitle">>},
 1351:     Res = user_change_room_config(Alice, ?NONEXISTENT_ROOM, RoomConfig, Config),
 1352:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1353: 
 1354: user_list_room_users(Config) ->
 1355:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1356:                                fun user_list_room_users_story/3).
 1357: 
 1358: user_list_room_users_story(Config, Alice, Bob) ->
 1359:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1360:     BobNick = <<"Bobek">>,
 1361:     AliceNick = <<"Ali">>,
 1362:     enter_room(RoomJID, Bob, BobNick),
 1363:     enter_room(RoomJID, Alice, AliceNick),
 1364:     Res = user_list_room_users(Alice, RoomJID, Config),
 1365:     ExpectedUsers = [{null, BobNick, <<"PARTICIPANT">>},
 1366:                      {null, AliceNick, <<"MODERATOR">>}],
 1367:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
 1368: 
 1369: user_list_room_users_without_anonymous_mode(Config) ->
 1370:     muc_helper:story_with_room(Config, [{anonymous, false}], [{alice, 1}, {bob, 1}],
 1371:                                fun user_list_room_users_without_anonymous_mode_story/3).
 1372: 
 1373: user_list_room_users_without_anonymous_mode_story(Config, Alice, Bob) ->
 1374:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1375:     BobNick = <<"Bobek">>,
 1376:     AliceNick = <<"Ali">>,
 1377:     enter_room(RoomJID, Bob, BobNick),
 1378:     enter_room(RoomJID, Alice, AliceNick),
 1379:     Res = user_list_room_users(Alice, RoomJID, Config),
 1380:     ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>},
 1381:                      {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}],
 1382:     assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)).
 1383: 
 1384: user_try_list_nonexistent_room_users(Config) ->
 1385:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1386:                                     fun user_try_list_nonexistent_room_users_story/2).
 1387: 
 1388: user_try_list_nonexistent_room_users_story(Config, Alice) ->
 1389:     Res = user_list_room_users(Alice, ?NONEXISTENT_ROOM, Config),
 1390:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1391: 
 1392: user_try_list_room_users_without_permission(Config) ->
 1393:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
 1394:                                fun user_try_list_room_users_without_permission_story/3).
 1395: 
 1396: user_try_list_room_users_without_permission_story(Config, _Alice, Bob) ->
 1397:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1398:     Res = user_list_room_users(Bob, RoomJID, Config),
 1399:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
 1400: 
 1401: user_get_room_messages(Config) ->
 1402:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1403:                                fun user_get_room_messages_story/3).
 1404: 
 1405: user_get_room_messages_story(Config, Alice, Bob) ->
 1406:     RoomJID = #jid{luser = RoomName, lserver = MUCDomain} =
 1407:         jid:from_binary(?config(room_jid, Config)),
 1408:     enter_room(RoomJID, Bob, <<"Bobek">>),
 1409:     enter_room(RoomJID, Alice, <<"Ali">>),
 1410:     escalus:wait_for_stanzas(Bob, 2),
 1411:     user_send_message_to_room(Bob, RoomJID, <<"Hi!">>, null, Config),
 1412:     escalus:wait_for_stanzas(Bob, 1),
 1413:     mam_helper:wait_for_room_archive_size(MUCDomain, RoomName, 1),
 1414:     Res = user_get_room_messages(Alice, RoomJID, 50, null, Config),
 1415:     #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} =
 1416:         get_ok_value(?GET_MESSAGES_PATH, Res),
 1417:     ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)).
 1418: 
 1419: user_shouldnt_store_messages_in_muc_light(Config) ->
 1420:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1421:                                     fun user_shouldnt_store_messages_in_muc_light_story/2).
 1422: 
 1423: user_shouldnt_store_messages_in_muc_light_story(Config, Alice) ->
 1424:     %% Create a MUC Light room
 1425:     MUCServer = ?config(muc_light_host, Config),
 1426:     AliceBin = escalus_client:short_jid(Alice),
 1427:     {ok, #{jid := RoomJID}} =
 1428:         create_muc_light_room(MUCServer, <<"first room">>, <<"subject">>, AliceBin),
 1429:     %% Send a message
 1430:     Message = <<"Hello friends">>,
 1431:     send_message_to_muc_light_room(RoomJID, jid:from_binary(AliceBin), Message),
 1432:     escalus:wait_for_stanza(Alice),
 1433:     %% Try to get a MUC Light message
 1434:     Limit = 1,
 1435:     Res = user_get_muc_light_room_messages(Alice, jid:to_binary(RoomJID), Limit, null, Config),
 1436:     #{<<"stanzas">> := [], <<"limit">> := Limit} =
 1437:         get_ok_value([data, muc_light, getRoomMessages], Res).
 1438: 
 1439: user_try_get_nonexistent_room_messages(Config) ->
 1440:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1441:                                     fun user_try_get_nonexistent_room_messages_story/2).
 1442: 
 1443: user_try_get_nonexistent_room_messages_story(Config, Alice) ->
 1444:     % Non-existent room with non-existent domain
 1445:     Res = user_get_room_messages(Alice, ?NONEXISTENT_ROOM, null, null, Config),
 1446:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)),
 1447:     % Non-existent room with existent domain
 1448:     Res2 = user_get_room_messages(Alice, ?NONEXISTENT_ROOM2, null, null, Config),
 1449:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"not found">>)).
 1450: 
 1451: user_try_get_room_messages_without_permission(Config) ->
 1452:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
 1453:                                fun user_try_get_room_messages_without_permission/3).
 1454: 
 1455: user_try_get_room_messages_without_permission(Config, _Alice, Bob) ->
 1456:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1457:     Res = user_get_room_messages(Bob, RoomJID, null, null, Config),
 1458:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
 1459: 
 1460: user_owner_set_user_affiliation(Config) ->
 1461:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1462:                                fun user_owner_set_user_affiliation/3).
 1463: 
 1464: user_owner_set_user_affiliation(Config, Alice, Bob) ->
 1465:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1466:     % Grant a member affiliation
 1467:     Res = user_set_user_affiliation(Alice, RoomJID, Bob, member, Config),
 1468:     assert_success(?SET_AFFILIATION_PATH, Res),
 1469:     assert_user_affiliation(RoomJID, Bob, member),
 1470:     % Grant a member affiliation
 1471:     Res1 = user_set_user_affiliation(Alice, RoomJID, Bob, admin, Config),
 1472:     assert_success(?SET_AFFILIATION_PATH, Res1),
 1473:     assert_user_affiliation(RoomJID, Bob, admin),
 1474:     % Grant a owner affiliation
 1475:     Res2 = user_set_user_affiliation(Alice, RoomJID, Bob, owner, Config),
 1476:     assert_success(?SET_AFFILIATION_PATH, Res2),
 1477:     assert_user_affiliation(RoomJID, Bob, owner),
 1478:     % Revoke affiliation
 1479:     Res3 = user_set_user_affiliation(Alice, RoomJID, Bob, none, Config),
 1480:     assert_success(?SET_AFFILIATION_PATH, Res3),
 1481:     assert_user_affiliation(RoomJID, Bob, none),
 1482:     % Ban user
 1483:     Res4 = user_set_user_affiliation(Alice, RoomJID, Bob, outcast, Config),
 1484:     assert_success(?SET_AFFILIATION_PATH, Res4),
 1485:     assert_user_affiliation(RoomJID, Bob, outcast).
 1486: 
 1487: 
 1488: user_admin_set_user_affiliation(Config) ->
 1489:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}, {kate, 1}],
 1490:                                fun user_admin_set_user_affiliation/4).
 1491: 
 1492: user_admin_set_user_affiliation(Config, Alice, Bob, Kate) ->
 1493:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1494:     user_set_user_affiliation(Alice, RoomJID, Bob, admin, Config),
 1495:     % Grant member affiliation
 1496:     Res = user_set_user_affiliation(Bob, RoomJID, Kate, member, Config),
 1497:     assert_success(?SET_AFFILIATION_PATH, Res),
 1498:     assert_user_affiliation(RoomJID, Kate, member),
 1499:     % Revoke affiliation
 1500:     Res1 = user_set_user_affiliation(Bob, RoomJID, Kate, none, Config),
 1501:     assert_success(?SET_AFFILIATION_PATH, Res1),
 1502:     assert_user_affiliation(RoomJID, Kate, none),
 1503:     % Admin cannot grant admin affiliation
 1504:     Res2 = user_set_user_affiliation(Bob, RoomJID, Kate, admin, Config),
 1505:     assert_no_permission(Res2),
 1506:     % Admin cannot grant owner affiliation
 1507:     Res3 = user_set_user_affiliation(Bob, RoomJID, Kate, owner, Config),
 1508:     assert_no_permission(Res3),
 1509:     % Admin can ban member
 1510:     Res4 = user_set_user_affiliation(Bob, RoomJID, Kate, outcast, Config),
 1511:     assert_success(?SET_AFFILIATION_PATH, Res4),
 1512:     assert_user_affiliation(RoomJID, Kate, outcast),
 1513:     % Admin cannot ban owner
 1514:     Res5 = user_set_user_affiliation(Bob, RoomJID, Alice, outcast, Config),
 1515:     assert_no_permission(Res5).
 1516: 
 1517: user_member_set_user_affiliation(Config) ->
 1518:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}, {kate, 1}],
 1519:                                fun user_member_set_user_affiliation/4).
 1520: 
 1521: user_member_set_user_affiliation(Config, Alice, Bob, Kate) ->
 1522:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1523:     user_set_user_affiliation(Alice, RoomJID, Bob, member, Config),
 1524:     % Member cannot grant member affiliation
 1525:     Res = user_set_user_affiliation(Bob, RoomJID, Kate, member, Config),
 1526:     assert_no_permission(Res),
 1527:     % Member cannot grant member admin affiliation
 1528:     Res1 = user_set_user_affiliation(Bob, RoomJID, Kate, admin, Config),
 1529:     assert_no_permission(Res1),
 1530:     % Member cannot grant member owner affiliation
 1531:     Res2 = user_set_user_affiliation(Bob, RoomJID, Kate, owner, Config),
 1532:     assert_no_permission(Res2),
 1533:     % Member cannot revoke member affiliation
 1534:     user_set_user_affiliation(Alice, RoomJID, Kate, member, Config),
 1535:     Res3 = user_set_user_affiliation(Bob, RoomJID, Kate, none, Config),
 1536:     assert_no_permission(Res3).
 1537: 
 1538: user_try_set_nonexistent_room_affiliation(Config) ->
 1539:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1540:                                     fun user_try_set_nonexistent_room_affiliation/2).
 1541: 
 1542: user_try_set_nonexistent_room_affiliation(Config, Alice) ->
 1543:     Res = user_set_user_affiliation(Alice, ?NONEXISTENT_ROOM, Alice, none, Config),
 1544:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1545: 
 1546: user_moderator_set_user_role(Config) ->
 1547:     muc_helper:story_with_room(Config, [{anonymous, false}, {persistent, true}],
 1548:                                [{alice, 1}, {bob, 1}],
 1549:                                fun user_moderator_set_user_role/3).
 1550: 
 1551: user_moderator_set_user_role(Config, Alice, Bob) ->
 1552:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1553:     BobNick = <<"Boobek">>,
 1554:     enter_room(RoomJID, Alice, escalus_client:username(Alice)),
 1555:     enter_room(RoomJID, Bob, BobNick),
 1556:     % Change from participant to visitor
 1557:     Res = user_set_user_role(Alice, RoomJID, BobNick, visitor, Config),
 1558:     assert_success(?SET_ROLE_PATH, Res),
 1559:     assert_user_role(RoomJID, Bob, visitor),
 1560:     % Change from visitor to participant
 1561:     Res1 = user_set_user_role(Alice, RoomJID, BobNick, participant, Config),
 1562:     assert_success(?SET_ROLE_PATH, Res1),
 1563:     assert_user_role(RoomJID, Bob, participant),
 1564:     % Change from participant to moderator
 1565:     Res2 = user_set_user_role(Alice, RoomJID, BobNick, moderator, Config),
 1566:     assert_success(?SET_ROLE_PATH, Res2),
 1567:     assert_user_role(RoomJID, Bob, moderator).
 1568: 
 1569: user_participant_set_user_role(Config) ->
 1570:     muc_helper:story_with_room(Config, [{anonymous, false}, {persistent, true}],
 1571:                                [{alice, 1}, {bob, 1}, {kate, 1}],
 1572:                                fun user_participant_set_user_role/4).
 1573: 
 1574: user_participant_set_user_role(Config, _Alice, Bob, Kate) ->
 1575:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1576:     BobNick = <<"Boobek">>,
 1577:     KateNick = <<"Katek">>,
 1578:     enter_room(RoomJID, Bob, BobNick),
 1579:     enter_room(RoomJID, Kate, KateNick),
 1580:     % Try change from participant to visitor
 1581:     Res = user_set_user_role(Bob, RoomJID, KateNick, visitor, Config),
 1582:     assert_no_permission(Res),
 1583:     % Change from participant to participant with success response
 1584:     Res1 = user_set_user_role(Bob, RoomJID, KateNick, participant, Config),
 1585:     assert_success(?SET_ROLE_PATH, Res1),
 1586:     assert_user_role(RoomJID, Bob, participant),
 1587:     % Try change from participant to moderator
 1588:     Res2 = user_set_user_role(Bob, RoomJID, KateNick, moderator, Config),
 1589:     assert_no_permission(Res2).
 1590: 
 1591: user_try_set_nonexistent_room_role(Config) ->
 1592:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1593:                                     fun user_try_set_nonexistent_room_role/2).
 1594: 
 1595: user_try_set_nonexistent_room_role(Config, Alice) ->
 1596:     Res = user_set_user_role(Alice, ?NONEXISTENT_ROOM, <<"Ali">>, participant, Config),
 1597:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1598: 
 1599: user_can_enter_room(Config) ->
 1600:     muc_helper:story_with_room(Config, [], [{alice, 1}], fun user_can_enter_room/2).
 1601: 
 1602: user_can_enter_room(Config, Alice) ->
 1603:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1604:     Nick = <<"ali">>,
 1605:     JID = jid:from_binary(escalus_utils:jid_to_lower(escalus_client:full_jid(Alice))),
 1606:     % Resource should be normalized to "res1", which is Alice's connected resource
 1607:     Res = user_enter_room(Alice, RoomJID, Nick, <<"res₁"/utf8>>, null, Config),
 1608:     assert_success(?ENTER_ROOM_PATH, Res),
 1609:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)).
 1610: 
 1611: user_cannot_enter_room_with_invalid_resource(Config) ->
 1612:     muc_helper:story_with_room(Config, [], [{alice, 1}],
 1613:                                fun user_cannot_enter_room_with_invalid_resource/2).
 1614: 
 1615: user_cannot_enter_room_with_invalid_resource(Config, Alice) ->
 1616:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1617:     Nick = <<"ali">>,
 1618:     Res1 = user_enter_room(Alice, RoomJID, Nick, <<"\n">>, null, Config),
 1619:     assert_coercion_err(Res1, <<"failed_to_parse_resource_name">>),
 1620:     Res2 = user_enter_room(Alice, RoomJID, Nick, <<>>, null, Config),
 1621:     assert_coercion_err(Res2, <<"empty_resource_name">>).
 1622: 
 1623: user_can_enter_room_with_password(Config) ->
 1624:     muc_helper:story_with_room(Config, [{password_protected, true}, {password, ?PASSWORD}],
 1625:                                [{alice, 1}, {bob, 1}],
 1626:                                fun user_can_enter_room_with_password/3).
 1627: 
 1628: user_can_enter_room_with_password(Config, Alice, Bob) ->
 1629:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1630:     Nick = <<"ali">>,
 1631:     JID = jid:from_binary(escalus_utils:jid_to_lower(escalus_client:full_jid(Alice))),
 1632:     Resource = escalus_client:resource(Alice),
 1633:     % Alice enter room with password
 1634:     Res = user_enter_room(Alice, RoomJID, Nick, Resource, ?PASSWORD, Config),
 1635:     assert_success(?ENTER_ROOM_PATH, Res),
 1636:     ?assertMatch([#{nick := Nick, jid := JID}], get_room_users(RoomJID)),
 1637:     % Bob try enter room without password
 1638:     Res1 = user_enter_room(Bob, RoomJID, <<"Bobek">>, Resource, null, Config),
 1639:     assert_success(?ENTER_ROOM_PATH, Res1),
 1640:     ?assertMatch([_], get_room_users(RoomJID)),
 1641:     % Bob enter room with password
 1642:     Res2 = user_enter_room(Bob, RoomJID, <<"Bobek">>, Resource, ?PASSWORD, Config),
 1643:     assert_success(?ENTER_ROOM_PATH, Res2),
 1644:     ?assertMatch([_, _], get_room_users(RoomJID)).
 1645: 
 1646: user_can_exit_room(Config) ->
 1647:     muc_helper:story_with_room(Config, [{persistent, true}], [{alice, 1}],
 1648:                                fun user_can_exit_room/2).
 1649: 
 1650: user_can_exit_room(Config, Alice) ->
 1651:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1652:     Nick = <<"ali">>,
 1653:     enter_room(RoomJID, Alice, Nick),
 1654:     ?assertMatch([_], get_room_users(RoomJID)),
 1655:     % Resource should be normalized to "res1", which is Alice's connected resource
 1656:     Res = user_exit_room(Alice, RoomJID, Nick, <<"res₁"/utf8>>, Config),
 1657:     assert_success(?EXIT_ROOM_PATH, Res),
 1658:     ?assertMatch([], get_room_users(RoomJID)).
 1659: 
 1660: user_list_room_affiliations(Config) ->
 1661:     muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}],
 1662:                                fun user_list_room_affiliations/3).
 1663: 
 1664: user_list_room_affiliations(Config, Alice, Bob) ->
 1665:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1666:     BobNick = <<"Bobek">>,
 1667:     AliceNick = <<"Ali">>,
 1668:     enter_room(RoomJID, Bob, BobNick),
 1669:     enter_room(RoomJID, Alice, AliceNick),
 1670:     AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
 1671:     BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
 1672:     % List all owners
 1673:     Res = user_list_room_affiliations(Alice, RoomJID, owner, Config),
 1674:     ?assertMatch([#{<<"jid">> := AliceJID, <<"affiliation">> := <<"OWNER">>}],
 1675:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res)),
 1676:     % List all members
 1677:     user_set_user_affiliation(Alice, RoomJID, Bob, member, Config),
 1678:     Res1 = user_list_room_affiliations(Alice, RoomJID, member, Config),
 1679:     ?assertMatch([#{<<"jid">> := BobJID, <<"affiliation">> := <<"MEMBER">>}],
 1680:                  get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res1)),
 1681:     % List all
 1682:     Res2 = user_list_room_affiliations(Alice, RoomJID, null, Config),
 1683:     ?assertMatch([_, _], get_ok_value(?LIST_ROOM_AFFILIATIONS_PATH, Res2)).
 1684: 
 1685: user_try_list_room_affiliations_without_permission(Config) ->
 1686:     muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}],
 1687:                                fun user_try_list_room_affiliations_without_permission/3).
 1688: 
 1689: user_try_list_room_affiliations_without_permission(Config, _Alice, Bob) ->
 1690:     RoomJID = jid:from_binary(?config(room_jid, Config)),
 1691:     Res = user_list_room_affiliations(Bob, RoomJID, null, Config),
 1692:     assert_no_permission(Res).
 1693: 
 1694: user_try_list_nonexistent_room_affiliations(Config) ->
 1695:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1696:                                     fun user_try_list_nonexistent_room_affiliations/2).
 1697: 
 1698: user_try_list_nonexistent_room_affiliations(Config, Alice) ->
 1699:     Res = user_list_room_affiliations(Alice, ?NONEXISTENT_ROOM, null, Config),
 1700:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)).
 1701: 
 1702: %% User MUC not configured test cases
 1703: 
 1704: user_delete_room_muc_not_configured(Config) ->
 1705:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1706:         fun user_delete_room_muc_not_configured_story/2).
 1707: 
 1708: user_delete_room_muc_not_configured_story(Config, Alice) ->
 1709:     Res = user_delete_room(Alice, get_room_name(), null, Config),
 1710:     get_not_loaded(Res).
 1711: 
 1712: user_list_room_users_muc_not_configured(Config) ->
 1713:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1714:         fun user_list_room_users_muc_not_configured_story/2).
 1715: 
 1716: user_list_room_users_muc_not_configured_story(Config, Alice) ->
 1717:     Res = user_list_room_users(Alice, get_room_name(), Config),
 1718:     get_not_loaded(Res).
 1719: 
 1720: user_change_room_config_muc_not_configured(Config) ->
 1721:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1722:         fun user_change_room_config_muc_not_configured_story/2).
 1723: 
 1724: user_change_room_config_muc_not_configured_story(Config, Alice) ->
 1725:     RoomConfig = #{title => <<"NewTitle">>},
 1726:     Res = user_change_room_config(Alice, get_room_name(), RoomConfig, Config),
 1727:     get_not_loaded(Res).
 1728: 
 1729: user_get_room_config_muc_not_configured(Config) ->
 1730:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1731:         fun user_get_room_config_muc_not_configured_story/2).
 1732: 
 1733: user_get_room_config_muc_not_configured_story(Config, Alice) ->
 1734:     Res = user_get_room_config(Alice, get_room_name(), Config),
 1735:     get_not_loaded(Res).
 1736: 
 1737: user_invite_user_muc_not_configured(Config) ->
 1738:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
 1739:         fun user_invite_user_muc_not_configured_story/3).
 1740: 
 1741: user_invite_user_muc_not_configured_story(Config, Alice, Bob) ->
 1742:     Res = user_invite_user(Alice, get_room_name(), Bob, null, Config),
 1743:     get_not_loaded(Res).
 1744: 
 1745: user_kick_user_muc_not_configured(Config) ->
 1746:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1747:         fun user_kick_user_muc_not_configured_story/2).
 1748: 
 1749: user_kick_user_muc_not_configured_story(Config, Alice) ->
 1750:     Res = user_kick_user(Alice, get_room_name(), <<"nick">>, <<"reason">>, Config),
 1751:     get_not_loaded(Res).
 1752: 
 1753: user_send_message_to_room_muc_not_configured(Config) ->
 1754:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1755:         fun user_send_message_to_room_muc_not_configured_story/2).
 1756: 
 1757: user_send_message_to_room_muc_not_configured_story(Config, Alice) ->
 1758:     Res = user_send_message_to_room(Alice, get_room_name(), <<"Body">>, null, Config),
 1759:     get_not_loaded(Res).
 1760: 
 1761: user_send_private_message_muc_not_configured(Config) ->
 1762:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1763:         fun user_send_private_message_muc_not_configured_story/2).
 1764: 
 1765: user_send_private_message_muc_not_configured_story(Config, Alice) ->
 1766:     Message = <<"Hello Bob!">>,
 1767:     BobNick = <<"Bobek">>,
 1768:     Res = user_send_private_message(Alice, get_room_name(), Message, BobNick, null, Config),
 1769:     get_not_loaded(Res).
 1770: 
 1771: user_get_room_messages_muc_or_mam_not_configured(Config) ->
 1772:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1773:         fun user_get_room_messages_muc_or_mam_not_configured_story/2).
 1774: 
 1775: user_get_room_messages_muc_or_mam_not_configured_story(Config, Alice) ->
 1776:     Res = user_get_room_messages(Alice, get_room_name(), 10, null, Config),
 1777:     get_not_loaded(Res).
 1778: 
 1779: user_owner_set_user_affiliation_muc_not_configured(Config) ->
 1780:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1781:         fun user_owner_set_user_affiliation_muc_not_configured_story/2).
 1782: 
 1783: user_owner_set_user_affiliation_muc_not_configured_story(Config, Alice) ->
 1784:     Res = user_set_user_affiliation(Alice, get_room_name(), Alice, member, Config),
 1785:     get_not_loaded(Res).
 1786: 
 1787: user_moderator_set_user_role_muc_not_configured(Config) ->
 1788:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1789:         fun user_moderator_set_user_role_muc_not_configured_story/2).
 1790: 
 1791: user_moderator_set_user_role_muc_not_configured_story(Config, Alice) ->
 1792:     Res = user_set_user_role(Alice, get_room_name(), Alice, moderator, Config),
 1793:     get_not_loaded(Res).
 1794: 
 1795: user_can_enter_room_muc_not_configured(Config) ->
 1796:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1797:         fun user_can_enter_room_muc_not_configured_story/2).
 1798: 
 1799: user_can_enter_room_muc_not_configured_story(Config, Alice) ->
 1800:     Nick = <<"ali">>,
 1801:     Resource = escalus_client:resource(Alice),
 1802:     Res = user_enter_room(Alice, get_room_name(), Nick, Resource, null, Config),
 1803:     get_not_loaded(Res).
 1804: 
 1805: user_can_exit_room_muc_not_configured(Config) ->
 1806:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1807:         fun user_can_exit_room_muc_not_configured_story/2).
 1808: 
 1809: user_can_exit_room_muc_not_configured_story(Config, Alice) ->
 1810:     Resource = escalus_client:resource(Alice),
 1811:     Res = user_exit_room(Alice, get_room_name(), <<"ali">>, Resource, Config),
 1812:     get_not_loaded(Res).
 1813: 
 1814: user_list_room_affiliations_muc_not_configured(Config) ->
 1815:     escalus:fresh_story_with_config(Config, [{alice, 1}],
 1816:         fun user_list_room_affiliations_muc_not_configured_story/2).
 1817: 
 1818: user_list_room_affiliations_muc_not_configured_story(Config, Alice) ->
 1819:     Res = user_list_room_affiliations(Alice, get_room_name(), owner, Config),
 1820:     get_not_loaded(Res).
 1821: 
 1822: %% Helpers
 1823: 
 1824: assert_coercion_err(Res, Code) ->
 1825:     ?assertNotEqual(nomatch, binary:match(get_coercion_err_msg(Res), Code)).
 1826: 
 1827: assert_no_full_jid(Res) ->
 1828:     assert_coercion_err(Res, <<"jid_without_resource">>).
 1829: 
 1830: assert_no_permission(Res) ->
 1831:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)).
 1832: 
 1833: assert_success(Path, Res) ->
 1834:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res), <<"successfully">>)).
 1835: 
 1836: get_room_affiliation(RoomJID, Aff) ->
 1837:     {ok, Affs} = rpc(mim(), mod_muc_api, get_room_affiliations, [RoomJID, Aff]),
 1838:     Affs.
 1839: 
 1840: get_room_users(RoomJID) ->
 1841:     {ok, Users} = rpc(mim(), mod_muc_api, get_room_users, [RoomJID]),
 1842:     Users.
 1843: 
 1844: assert_user_role(RoomJID, User, Role) ->
 1845:     UserJID = jid:from_binary(escalus_client:full_jid(User)),
 1846:     ?assert(lists:any(fun(#{jid := JID, role := Role2}) ->
 1847:                               Role =:= Role2 andalso jid:are_bare_equal(JID, UserJID) end,
 1848:                       get_room_users(RoomJID))).
 1849: 
 1850: assert_user_affiliation(RoomJID, User, none) ->
 1851:     Affs = get_room_affiliation(RoomJID, undefined),
 1852:     UserSimpleJID = jid:to_lower(user_to_jid(User)),
 1853:     ?assertNot(lists:any(fun({U, _}) -> U == UserSimpleJID end, Affs));
 1854: assert_user_affiliation(RoomJID, User, Aff) ->
 1855:     Affs = get_room_affiliation(RoomJID, Aff),
 1856:     Elem = {jid:to_lower(user_to_jid(User)), Aff},
 1857:     ?assert(lists:member(Elem, Affs)).
 1858: 
 1859: rand_name() ->
 1860:     rpc(mim(), mongoose_bin, gen_from_crypto, []).
 1861: 
 1862: -spec assert_room_users([{jid:jid(), binary(), binary()}], [map()]) -> ok.
 1863: assert_room_users(Expected, Actual) ->
 1864:     ActualTuples = [{JID, Nick, Role} || #{<<"jid">> := JID, <<"role">> := Role, <<"nick">> := Nick} <- Actual],
 1865:     ?assertEqual(lists:sort(Expected), lists:sort(ActualTuples)).
 1866: 
 1867: assert_is_message_correct(RoomJID, SenderNick, Type, Text, ReceivedMessage) ->
 1868:     escalus_pred:is_message(ReceivedMessage),
 1869:     From = jid:to_binary(jid:replace_resource(RoomJID, SenderNick)),
 1870:     From = exml_query:attr(ReceivedMessage, <<"from">>),
 1871:     Type = exml_query:attr(ReceivedMessage, <<"type">>),
 1872:     Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content=Text}]},
 1873:     Body = exml_query:subelement(ReceivedMessage, <<"body">>).
 1874: 
 1875: enter_room(RoomJID, User, Nick) ->
 1876:     JID = jid:to_binary(jid:replace_resource(RoomJID, Nick)),
 1877:     Pres = escalus_stanza:to(escalus_stanza:presence(<<"available">>,
 1878:         [#xmlel{ name = <<"x">>, attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]),
 1879:         JID),
 1880:     escalus:send(User, Pres),
 1881:     escalus:wait_for_stanza(User).
 1882: 
 1883: contain_room(Name, #{<<"rooms">> := Rooms}) ->
 1884:     contain_room(Name, Rooms);
 1885: contain_room(Name, Rooms) when is_list(Rooms) ->
 1886:     lists:any(fun(#{<<"title">> := T}) -> T =:= Name end, Rooms).
 1887: 
 1888: extract_rooms(#{<<"rooms">> := [], <<"index">> := null, <<"count">> := 0,
 1889:                 <<"first">> := null, <<"last">> := null}) ->
 1890:     [];
 1891: extract_rooms(#{<<"rooms">> := Rooms, <<"index">> := Index, <<"count">> := Count,
 1892:                 <<"first">> := First, <<"last">> := Last}) ->
 1893:     Titles = lists:map(fun(#{<<"title">> := Title}) -> Title end, Rooms),
 1894:     ?assertEqual(hd(Titles), First),
 1895:     ?assertEqual(lists:last(Titles), Last),
 1896:     ?assert(is_integer(Count) andalso Count >= length(Titles)),
 1897:     ?assert(is_integer(Index) andalso Index >= 0),
 1898:     Titles.
 1899: 
 1900: returned_rooms(#{<<"rooms">> := Rooms}) ->
 1901:     [Title || #{<<"title">> := Title} <- Rooms].
 1902: 
 1903: assert_default_room_config(Response) ->
 1904:     ?assertMatch(#{<<"title">> := <<>>,
 1905:                    <<"description">> := <<>>,
 1906:                    <<"allowChangeSubject">> := true,
 1907:                    <<"allowQueryUsers">> := true,
 1908:                    <<"allowPrivateMessages">> := true,
 1909:                    <<"allowVisitorStatus">> := true,
 1910:                    <<"allowVisitorNickchange">> := true,
 1911:                    <<"public">> := true,
 1912:                    <<"publicList">> := true,
 1913:                    <<"persistent">> := false,
 1914:                    <<"moderated">> := true,
 1915:                    <<"membersByDefault">> := true,
 1916:                    <<"membersOnly">> := false,
 1917:                    <<"allowUserInvites">> := false,
 1918:                    <<"allowMultipleSession">> := false,
 1919:                    <<"passwordProtected">> := false,
 1920:                    <<"password">> := <<>>,
 1921:                    <<"anonymous">> := true,
 1922:                    <<"mayGetMemberList">> := [],
 1923:                    <<"maxUsers">> := 200,
 1924:                    <<"logging">> := false}, get_ok_value(?GET_ROOM_CONFIG_PATH, Response)).
 1925: 
 1926: atom_to_enum_item(null) -> null;
 1927: atom_to_enum_item(Atom) -> list_to_binary(string:to_upper(atom_to_list(Atom))).
 1928: 
 1929: get_room_name() ->
 1930:     Domain = domain_helper:domain(),
 1931:     <<"NON_EXISTING@", Domain/binary>>.
 1932: 
 1933: %% Commands
 1934: 
 1935: create_muc_light_room(Domain, Name, Subject, CreatorBin) ->
 1936:     CreatorJID = jid:from_binary(CreatorBin),
 1937:     Config = #{<<"roomname">> => Name, <<"subject">> => Subject},
 1938:     rpc(mim(), mod_muc_light_api, create_room, [Domain, CreatorJID, Config]).
 1939: 
 1940: create_instant_room(Room, Owner, Nick, Config) ->
 1941:     Vars = #{room => room_to_bin(Room), owner => user_to_bin(Owner), nick => Nick},
 1942:     execute_command(<<"muc">>, <<"createInstantRoom">>, Vars, Config).
 1943: 
 1944: invite_user(Room, Sender, Recipient, Reason, Config) ->
 1945:     Vars = #{room => jid:to_binary(Room), sender => user_to_bin(Sender),
 1946:              recipient => user_to_bin(Recipient), reason => Reason},
 1947:     execute_command(<<"muc">>, <<"inviteUser">>, Vars, Config).
 1948: 
 1949: kick_user(Room, Nick, Reason, Config) ->
 1950:     Vars = #{room => jid:to_binary(Room), nick => Nick, reason => Reason},
 1951:     execute_command(<<"muc">>, <<"kickUser">>, Vars, Config).
 1952: 
 1953: send_message_to_room(Room, From, Body, Config) ->
 1954:     Vars = #{room => jid:to_binary(Room), from => user_to_full_bin(From), body => Body},
 1955:     execute_command(<<"muc">>, <<"sendMessageToRoom">>, Vars, Config).
 1956: 
 1957: send_private_message(Room, From, ToNick, Body, Config) ->
 1958:     Vars = #{room => jid:to_binary(Room), from => user_to_full_bin(From),
 1959:              toNick => ToNick, body => Body},
 1960:     execute_command(<<"muc">>, <<"sendPrivateMessage">>, Vars, Config).
 1961: 
 1962: send_message_to_muc_light_room(RoomJID, SenderJID, Message) ->
 1963:     rpc(mim(), mod_muc_light_api, send_message, [RoomJID, SenderJID, Message]).
 1964: 
 1965: enter_room(Room, User, Nick, Password, Config) ->
 1966:     Vars = #{room => jid:to_binary(Room), user => user_to_full_bin(User),
 1967:              nick => Nick, password => Password},
 1968:     execute_command(<<"muc">>, <<"enterRoom">>, Vars, Config).
 1969: 
 1970: delete_room(Room, Reason, Config) ->
 1971:     Vars = #{room => jid:to_binary(Room), reason => Reason},
 1972:     execute_command(<<"muc">>, <<"deleteRoom">>, Vars, Config).
 1973: 
 1974: change_room_config(Room, RoomConfig, Config) ->
 1975:     Vars = #{room => jid:to_binary(Room), config => RoomConfig},
 1976:     execute_command(<<"muc">>, <<"changeRoomConfiguration">>, Vars, Config).
 1977: 
 1978: list_rooms(MUCDomain, From, Limit, Index, Config) ->
 1979:     Vars = #{mucDomain => MUCDomain, from => user_to_bin(From), limit => Limit, index => Index},
 1980:     execute_command(<<"muc">>, <<"listRooms">>, Vars, Config).
 1981: 
 1982: get_room_config(Room, Config) ->
 1983:     Vars = #{room => jid:to_binary(Room)},
 1984:     execute_command(<<"muc">>, <<"getRoomConfig">>, Vars, Config).
 1985: 
 1986: list_room_users(RoomJID, Config) ->
 1987:     Vars = #{room => jid:to_binary(RoomJID)},
 1988:     execute_command(<<"muc">>, <<"listRoomUsers">>, Vars, Config).
 1989: 
 1990: get_room_messages(RoomJID, PageSize, Before, Config) ->
 1991:     Vars = #{<<"room">> => jid:to_binary(RoomJID), <<"pageSize">> => PageSize,
 1992:              <<"before">> => Before},
 1993:     execute_command(<<"muc">>, <<"getRoomMessages">>, Vars, Config).
 1994: 
 1995: set_user_affiliation(Room, User, Aff, Config) ->
 1996:     Vars = #{room => jid:to_binary(Room), user => user_to_bin(User),
 1997:              affiliation => atom_to_enum_item(Aff)},
 1998:     execute_command(<<"muc">>, <<"setUserAffiliation">>, Vars, Config).
 1999: 
 2000: set_user_role(Room, User, Role, Config) ->
 2001:     Vars = #{room => jid:to_binary(Room), nick => user_to_bin(User),
 2002:              role => atom_to_enum_item(Role)},
 2003:     execute_command(<<"muc">>, <<"setUserRole">>, Vars, Config).
 2004: 
 2005: exit_room(Room, User, Nick, Config) ->
 2006:     Vars = #{room => jid:to_binary(Room), user => user_to_full_bin(User), nick => Nick},
 2007:     execute_command(<<"muc">>, <<"exitRoom">>, Vars, Config).
 2008: 
 2009: list_room_affiliations(Room, Aff, Config) ->
 2010:     Vars = #{room => jid:to_binary(Room), affiliation => atom_to_enum_item(Aff)},
 2011:     execute_command(<<"muc">>, <<"listRoomAffiliations">>, Vars, Config).
 2012: 
 2013: user_kick_user(User, Room, Nick, Reason, Config) ->
 2014:     Vars = #{room => jid:to_binary(Room), nick => Nick, reason => Reason},
 2015:     execute_user_command(<<"muc">>, <<"kickUser">>, User, Vars, Config).
 2016: 
 2017: user_enter_room(User, Room, Nick, Resource, Password, Config) ->
 2018:     Vars = #{room => jid:to_binary(Room), nick => Nick, resource => Resource, password => Password},
 2019:     execute_user_command(<<"muc">>, <<"enterRoom">>, User, Vars, Config).
 2020: 
 2021: user_get_room_messages(User, RoomJID, PageSize, Before, Config) ->
 2022:     Vars = #{<<"room">> => jid:to_binary(RoomJID), <<"pageSize">> => PageSize,
 2023:              <<"before">> => Before},
 2024:     execute_user_command(<<"muc">>, <<"getRoomMessages">>, User, Vars, Config).
 2025: 
 2026: user_get_muc_light_room_messages(User, RoomJID, PageSize, Before, Config) ->
 2027:     Vars = #{<<"room">> => RoomJID, <<"pageSize">> => PageSize, <<"before">> => Before},
 2028:     execute_user_command(<<"muc_light">>, <<"getRoomMessages">>, User, Vars, Config).
 2029: 
 2030: user_delete_room(User, Room, Reason, Config) ->
 2031:     Vars = #{room => jid:to_binary(Room), reason => Reason},
 2032:     execute_user_command(<<"muc">>, <<"deleteRoom">>, User, Vars, Config).
 2033: 
 2034: user_change_room_config(User, Room, RoomConfig, Config) ->
 2035:     Vars = #{room => jid:to_binary(Room), config => RoomConfig},
 2036:     execute_user_command(<<"muc">>, <<"changeRoomConfiguration">>, User, Vars, Config).
 2037: 
 2038: user_list_rooms(User, MUCDomain, Limit, Index, Config) ->
 2039:     Vars = #{mucDomain => MUCDomain, limit => Limit, index => Index},
 2040:     execute_user_command(<<"muc">>, <<"listRooms">>, User, Vars, Config).
 2041: 
 2042: user_get_room_config(User, Room, Config) ->
 2043:     Vars = #{room => jid:to_binary(Room)},
 2044:     execute_user_command(<<"muc">>, <<"getRoomConfig">>, User, Vars, Config).
 2045: 
 2046: user_list_room_users(User, RoomJID, Config) ->
 2047:     Vars = #{room => jid:to_binary(RoomJID)},
 2048:     execute_user_command(<<"muc">>, <<"listRoomUsers">>, User, Vars, Config).
 2049: 
 2050: user_send_message_to_room(User, Room, Body, Resource, Config) ->
 2051:     Vars = #{room => jid:to_binary(Room), body => Body, resource => Resource},
 2052:     execute_user_command(<<"muc">>, <<"sendMessageToRoom">>, User, Vars, Config).
 2053: 
 2054: user_send_private_message(User, Room, Body, ToNick, Resource, Config) ->
 2055:     Vars = #{room => jid:to_binary(Room), body => Body, toNick => ToNick, resource => Resource},
 2056:     execute_user_command(<<"muc">>, <<"sendPrivateMessage">>, User, Vars, Config).
 2057: 
 2058: user_create_instant_room(User, Room, Nick, Config) ->
 2059:     Vars = #{room => room_to_bin(Room), nick => Nick},
 2060:     execute_user_command(<<"muc">>, <<"createInstantRoom">>, User, Vars, Config).
 2061: 
 2062: user_invite_user(User, Room, Recipient, Reason, Config) ->
 2063:     Vars = #{room => jid:to_binary(Room), recipient => user_to_bin(Recipient), reason => Reason},
 2064:     execute_user_command(<<"muc">>, <<"inviteUser">>, User, Vars, Config).
 2065: 
 2066: user_set_user_affiliation(User, Room, QueriedUser, Aff, Config) ->
 2067:     Vars = #{room => jid:to_binary(Room), user => user_to_bin(QueriedUser),
 2068:              affiliation => atom_to_enum_item(Aff)},
 2069:     execute_user_command(<<"muc">>, <<"setUserAffiliation">>, User, Vars, Config).
 2070: 
 2071: user_set_user_role(User, Room, QueriedUser, Role, Config) ->
 2072:     Vars = #{room => jid:to_binary(Room), nick => user_to_bin(QueriedUser),
 2073:              role => atom_to_enum_item(Role)},
 2074:     execute_user_command(<<"muc">>, <<"setUserRole">>, User, Vars, Config).
 2075: 
 2076: user_exit_room(User, Room, Nick, Resource, Config) ->
 2077:     Vars = #{room => jid:to_binary(Room), resource => Resource, nick => Nick},
 2078:     execute_user_command(<<"muc">>, <<"exitRoom">>, User, Vars, Config).
 2079: 
 2080: user_list_room_affiliations(User, Room, Aff, Config) ->
 2081:     Vars = #{room => jid:to_binary(Room), affiliation => atom_to_enum_item(Aff)},
 2082:     execute_user_command(<<"muc">>, <<"listRoomAffiliations">>, User, Vars, Config).
 2083: 
 2084: room_to_bin(RoomJIDBin) when is_binary(RoomJIDBin) ->RoomJIDBin;
 2085: room_to_bin(RoomJID) -> jid:to_binary(RoomJID).