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