./ct_report/coverage/mod_muc_api.COVER.html

1 %% @doc Provide an interface for frontends (like graphql or ctl) to manage MUC rooms.
2 -module(mod_muc_api).
3
4 -export([get_rooms/4,
5 get_room_config/1,
6 get_room_config/2,
7 get_room_messages/3,
8 get_room_messages/4,
9 modify_room_config/2,
10 modify_room_config/3,
11 get_room_users/1,
12 get_room_users/2,
13 get_room_affiliations/2,
14 get_room_affiliations/3,
15 create_instant_room/3,
16 invite_to_room/4,
17 send_message_to_room/3,
18 send_private_message/4,
19 kick_user_from_room/3,
20 kick_user_from_room/4,
21 set_affiliation/3,
22 set_affiliation/4,
23 enter_room/3,
24 exit_room/2,
25 set_role/4,
26 set_role/3,
27 delete_room/2,
28 delete_room/3]).
29
30 -ignore_xref([get_rooms/4, get_rooms/5, delete_room/3,
31 get_room_config/2, get_room_users/2]).
32
33 -include("jlib.hrl").
34 -include("mongoose_rsm.hrl").
35 -include("mod_muc_room.hrl").
36
37 -type short_room_desc() :: #{jid := jid:jid(),
38 title := binary(),
39 private => boolean(),
40 users_number => non_neg_integer()}.
41
42 -type get_rooms_result() :: {[short_room_desc()], jlib:rsm_out()}.
43
44 -type user_map() ::
45 #{jid := jid:jid() | null,
46 role := mod_muc:role(),
47 nick := mod_muc:nick()}.
48
49 -type room_conf_mod_fun() :: fun((mod_muc_room:config()) -> mod_muc_room:config()).
50
51 -type aff_item() :: {jid:simple_jid(), mod_muc:affiliation()}.
52
53 -export_type([user_map/0, short_room_desc/0]).
54
55 -define(ROOM_DELETED_SUCC_RESULT, {ok, "Room deleted successfully"}).
56 -define(USER_CANNOT_ACCESS_ROOM_RESULT,
57 {not_allowed, "Given user does not have permission to read this room"}).
58 -define(ROOM_NOT_FOUND_RESULT, {room_not_found, "Room not found"}).
59 -define(DELETE_NONEXISTENT_ROOM_RESULT, {room_not_found, "Cannot remove non-existent room"}).
60 -define(USER_NOT_FOUND_RESULT, {user_not_found, "Given user not found"}).
61 -define(MUC_SERVER_NOT_FOUND_RESULT, {muc_server_not_found, "MUC server not found"}).
62 -define(MODERATOR_NOT_FOUND_RESULT, {moderator_not_found, "Moderator user not found"}).
63 -define(MODERATOR_RES_NOT_FOUND_RESULT,
64 {moderator_not_found, "Resource with moderator role not found"}).
65 -define(SET_ROLE_SUCC_RESULT, {ok, "Role set successfully"}).
66
67 -spec get_rooms(jid:lserver(), jid:jid(), non_neg_integer() | undefined,
68 non_neg_integer()) -> {ok, get_rooms_result()} | {muc_server_not_found, iolist()}.
69 get_rooms(MUCServer, From, Limit, Index) ->
70
:-(
case mongoose_domain_api:get_subdomain_host_type(MUCServer) of
71 {ok, _HostType} ->
72
:-(
{Rooms, RSM} = mod_muc:get_vh_rooms(MUCServer, #rsm_in{max = Limit, index = Index}),
73
:-(
Rooms2 = lists:filtermap(fun(R) -> room_to_item(R, MUCServer, From) end, Rooms),
74
:-(
{ok, {Rooms2, RSM}};
75 {error, not_found} ->
76
:-(
?MUC_SERVER_NOT_FOUND_RESULT
77 end.
78
79 -spec get_room_config(jid:jid(), jid:jid()) ->
80 {ok, mod_muc_room:config()} | {not_allowed | room_not_found, iolist()}.
81 get_room_config(RoomJID, UserJID) ->
82
:-(
case mod_muc_room:is_room_owner(RoomJID, UserJID) of
83 {ok, true} ->
84
:-(
{ok, Config} = mod_muc_room:get_room_config(RoomJID),
85
:-(
{ok, Config};
86 {ok, false} ->
87
:-(
{not_allowed, "Given user does not have permission to read config"};
88 {error, not_found} ->
89
:-(
?ROOM_NOT_FOUND_RESULT
90 end.
91
92 -spec get_room_config(jid:jid()) -> {ok, mod_muc_room:config()} | {room_not_found, iolist()}.
93 get_room_config(RoomJID) ->
94
:-(
case mod_muc_room:get_room_config(RoomJID) of
95 {ok, Config} ->
96
:-(
{ok, Config};
97 {error, not_found} ->
98
:-(
?ROOM_NOT_FOUND_RESULT
99 end.
100
101 -spec create_instant_room(jid:jid(), jid:jid(), binary()) ->
102 {ok, short_room_desc()} | {internal | user_not_found | room_not_found, iolist()}.
103 create_instant_room(BareRoomJID = #jid{luser = Name, lresource = <<>>}, OwnerJID, Nick) ->
104 %% Because these stanzas are sent on the owner's behalf through
105 %% the HTTP API, they will certainly receive stanzas as a
106 %% consequence, even if their client(s) did not initiate this.
107
:-(
case ejabberd_auth:does_user_exist(OwnerJID) of
108 true ->
109
:-(
UserRoomJID = jid:replace_resource(BareRoomJID, Nick),
110 %% Send presence to create a room.
111
:-(
ejabberd_router:route(OwnerJID, UserRoomJID,
112 presence(OwnerJID, UserRoomJID, undefined)),
113 %% Send IQ set to unlock the room.
114
:-(
ejabberd_router:route(OwnerJID, BareRoomJID,
115 declination(OwnerJID, BareRoomJID)),
116
:-(
case verify_room(BareRoomJID, OwnerJID) of
117 ok ->
118
:-(
{ok, #{jid => BareRoomJID, title => Name, private => false, users_number => 0}};
119 Error ->
120
:-(
Error
121 end;
122 false ->
123
:-(
?USER_NOT_FOUND_RESULT
124 end.
125
126 -spec modify_room_config(jid:jid(), jid:jid(), room_conf_mod_fun()) ->
127 {ok, mod_muc_room:config()} | {not_allowed | room_not_found, iolist()}.
128 modify_room_config(RoomJID, UserJID, Fun) ->
129
:-(
case mod_muc_room:is_room_owner(RoomJID, UserJID) of
130 {ok, true} ->
131
:-(
{ok, modify_room_config_raw(RoomJID, Fun)};
132 {ok, false} ->
133
:-(
{not_allowed, "Given user does not have permission to change the config"};
134 {error, not_found} ->
135
:-(
?ROOM_NOT_FOUND_RESULT
136 end.
137
138 -spec modify_room_config(jid:jid(), room_conf_mod_fun()) ->
139 {ok, mod_muc_room:config()} | {room_not_found, iolist()}.
140 modify_room_config(RoomJID, Fun) ->
141
:-(
case mod_muc:room_jid_to_pid(RoomJID) of
142 {ok, _} ->
143
:-(
{ok, modify_room_config_raw(RoomJID, Fun)};
144 {error, not_found} ->
145
:-(
?ROOM_NOT_FOUND_RESULT
146 end.
147
148 -spec invite_to_room(jid:jid(), jid:jid(), jid:jid(), binary()) ->
149 {ok | internal | room_not_found, iolist()}.
150 invite_to_room(RoomJID, SenderJID, RecipientJID, Reason) ->
151
:-(
case verify_room(RoomJID, SenderJID) of
152 ok ->
153
:-(
Attrs = case get_room_config(RoomJID) of
154 {ok, #config{password_protected = true, password = Pass}} ->
155
:-(
[{<<"password">>, Pass}];
156 _ ->
157
:-(
[]
158 end,
159 %% Direct invitation: i.e. not mediated by MUC room. See XEP 0249.
160
:-(
X = #xmlel{name = <<"x">>,
161 attrs = [{<<"xmlns">>, ?NS_CONFERENCE},
162 {<<"jid">>, jid:to_binary(RoomJID)},
163 {<<"reason">>, Reason} | Attrs]
164 },
165
:-(
Invite = message(SenderJID, RecipientJID, <<>>, [X]),
166
:-(
ejabberd_router:route(SenderJID, RecipientJID, Invite),
167
:-(
{ok, "Invitation sent successfully"};
168 Error ->
169
:-(
Error
170 end.
171
172 -spec send_message_to_room(jid:jid(), jid:jid(), binary()) -> {ok, iolist()}.
173 send_message_to_room(RoomJID, SenderJID, Message) ->
174
:-(
Body = #xmlel{name = <<"body">>,
175 children = [#xmlcdata{content = Message}]},
176
:-(
Stanza = message(SenderJID, RoomJID, <<"groupchat">>, [Body]),
177
:-(
ejabberd_router:route(SenderJID, RoomJID, Stanza),
178
:-(
{ok, "Message sent successfully"}.
179
180 -spec send_private_message(jid:jid(), jid:jid(), binary(), binary()) -> {ok, iolist()}.
181 send_private_message(RoomJID, SenderJID, ToNick, Message) ->
182
:-(
RoomJIDRes = jid:replace_resource(RoomJID, ToNick),
183
:-(
Body = #xmlel{name = <<"body">>,
184 children = [#xmlcdata{content = Message}]},
185
:-(
X = #xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}]},
186
:-(
Stanza = message(SenderJID, RoomJID, <<"chat">>, [Body, X]),
187
:-(
ejabberd_router:route(SenderJID, RoomJIDRes, Stanza),
188
:-(
{ok, "Message sent successfully"}.
189
190 -spec kick_user_from_room(jid:jid(), binary(), binary()) ->
191 {ok | room_not_found | moderator_not_found, iolist()}.
192 kick_user_from_room(RoomJID, Nick, ReasonIn) ->
193 %% All the machinery which is already deeply embedded in the MUC
194 %% modules will perform the neccessary checking.
195
:-(
case room_moderator(RoomJID) of
196 {ok, SenderJID} ->
197
:-(
kick_user_from_room_raw(RoomJID, SenderJID, Nick, ReasonIn);
198 {error, moderator_not_found} ->
199
:-(
?MODERATOR_NOT_FOUND_RESULT;
200 {error, not_found} ->
201
:-(
?ROOM_NOT_FOUND_RESULT
202 end.
203
204 -spec kick_user_from_room(jid:jid(), jid:jid(), binary(), binary()) ->
205 {ok | room_not_found | moderator_not_found, iolist()}.
206 kick_user_from_room(RoomJID, UserJID, Nick, ReasonIn) ->
207 %% All the machinery which is already deeply embedded in the MUC
208 %% modules will perform the neccessary checking.
209
:-(
case try_add_role_resource(RoomJID, UserJID, moderator) of
210 {ok, #jid{lresource = <<>>}} ->
211
:-(
?MODERATOR_RES_NOT_FOUND_RESULT;
212 {ok, SenderJID} ->
213
:-(
kick_user_from_room_raw(RoomJID, SenderJID, Nick, ReasonIn);
214 {error, not_found} ->
215
:-(
?ROOM_NOT_FOUND_RESULT
216 end.
217
218 -spec delete_room(jid:jid(), binary()) -> {ok | room_not_found, iolist()}.
219 delete_room(RoomJID, Reason) ->
220
:-(
case mod_muc_room:delete_room(RoomJID, Reason) of
221 ok ->
222
:-(
?ROOM_DELETED_SUCC_RESULT;
223 {error, not_found} ->
224
:-(
?DELETE_NONEXISTENT_ROOM_RESULT
225 end.
226
227 -spec delete_room(jid:jid(), jid:jid(), binary()) ->
228 {ok | not_allowed | room_not_found, iolist()}.
229 delete_room(RoomJID, OwnerJID, Reason) ->
230
:-(
case mod_muc_room:is_room_owner(RoomJID, OwnerJID) of
231 {ok, true} ->
232
:-(
ok = mod_muc_room:delete_room(RoomJID, Reason),
233
:-(
?ROOM_DELETED_SUCC_RESULT;
234 {ok, false} ->
235
:-(
{not_allowed, "Given user does not have permission to delete this room"};
236 {error, not_found} ->
237
:-(
?DELETE_NONEXISTENT_ROOM_RESULT
238 end.
239
240 -spec get_room_users(jid:jid()) -> {ok, [user_map()]} | {room_not_found, iolist()}.
241 get_room_users(RoomJID) ->
242
:-(
case mod_muc_room:get_room_users(RoomJID) of
243 {ok, Users} ->
244
:-(
{ok, [to_user_map(U, true) || U <- Users]};
245 {error, not_found} ->
246
:-(
?ROOM_NOT_FOUND_RESULT
247 end.
248
249 -spec get_room_users(jid:jid(), jid:jid()) ->
250 {ok, [user_map()]} | {not_allowed | room_not_found, iolist()}.
251 get_room_users(RoomJID, UserJID) ->
252
:-(
case mod_muc_room:can_access_room(RoomJID, UserJID) of
253 {ok, true} ->
254
:-(
{ok, Users} = mod_muc_room:get_room_users(RoomJID),
255
:-(
{ok, WithJID} = mod_muc_room:can_access_identity(RoomJID, UserJID),
256
:-(
{ok, [to_user_map(U, WithJID) || U <- Users]};
257 {ok, false} ->
258
:-(
?USER_CANNOT_ACCESS_ROOM_RESULT;
259 {error, not_found} ->
260
:-(
?ROOM_NOT_FOUND_RESULT
261 end.
262
263 -spec get_room_messages(jid:jid(), integer() | undefined,
264 mod_mam:unix_timestamp() | undefined) ->
265 {ok, [mod_mam:message_row()]} | {muc_server_not_found | internal, iolist()}.
266 get_room_messages(RoomJID, PageSize, Before) ->
267
:-(
case mongoose_domain_api:get_subdomain_host_type(RoomJID#jid.lserver) of
268 {ok, HostType} ->
269
:-(
mod_muc_light_api:get_room_messages(HostType, RoomJID, undefined, PageSize, Before);
270 {error, not_found} ->
271
:-(
?MUC_SERVER_NOT_FOUND_RESULT
272 end.
273
274 -spec get_room_messages(jid:jid(), jid:jid(), integer() | undefined,
275 mod_mam:unix_timestamp() | undefined) ->
276 {ok, list()} | {muc_server_not_found | room_not_found | internal | not_allowed, iolist()}.
277 get_room_messages(RoomJID, UserJID, PageSize, Before) ->
278
:-(
case mongoose_domain_api:get_subdomain_host_type(RoomJID#jid.lserver) of
279 {ok, HostType} ->
280
:-(
case mod_muc_room:can_access_room(RoomJID, UserJID) of
281 {ok, true} ->
282
:-(
mod_muc_light_api:get_room_messages(HostType, RoomJID, UserJID,
283 PageSize, Before);
284 {ok, false} ->
285
:-(
?USER_CANNOT_ACCESS_ROOM_RESULT;
286 {error, not_found} ->
287
:-(
?ROOM_NOT_FOUND_RESULT
288 end;
289 {error, not_found} ->
290
:-(
?MUC_SERVER_NOT_FOUND_RESULT
291 end.
292
293 -spec get_room_affiliations(jid:jid(), jid:jid(), mod_muc:affiliation() | undefined) ->
294 {ok, [aff_item()]} | {not_allowed | room_not_found, iolist()}.
295 get_room_affiliations(RoomJID, UserJID, AffType) ->
296
:-(
case mod_muc_room:can_access_room(RoomJID, UserJID) of
297 {ok, true} ->
298
:-(
get_room_affiliations(RoomJID, AffType);
299 {ok, false} ->
300
:-(
?USER_CANNOT_ACCESS_ROOM_RESULT;
301 {error, not_found} ->
302
:-(
?ROOM_NOT_FOUND_RESULT
303 end.
304
305 -spec get_room_affiliations(jid:jid(), mod_muc:affiliation() | undefined) ->
306 {ok, [aff_item()]} | {room_not_found, iolist()}.
307 get_room_affiliations(RoomJID, AffType) ->
308
:-(
case room_users_aff(RoomJID) of
309 {ok, Affiliations} ->
310
:-(
Res = filter_affs_by_type(AffType, Affiliations),
311
:-(
{ok, Res};
312 {error, not_found} ->
313
:-(
?ROOM_NOT_FOUND_RESULT
314 end.
315
316 -spec set_affiliation(jid:jid(), jid:jid(), mod_muc:affiliation()) ->
317 {ok | room_not_found | not_allowed, iolist()}.
318 set_affiliation(RoomJID, UserJID, Affiliation) ->
319
:-(
case room_users_aff(RoomJID) of
320 {ok, Affs} ->
321
:-(
{OwnerJID, owner} = hd(filter_affs_by_type(owner, Affs)),
322
:-(
set_affiliation(RoomJID, OwnerJID, UserJID, Affiliation);
323 {error, not_found} ->
324
:-(
?ROOM_NOT_FOUND_RESULT
325 end.
326
327 -spec set_affiliation(jid:jid(), jid:jid(), jid:jid(), mod_muc:affiliation()) ->
328 {ok | room_not_found | not_allowed, iolist()}.
329 set_affiliation(RoomJID, FromJID, UserJID, Affiliation) ->
330
:-(
AffItem = affiliation_item(UserJID, Affiliation),
331
:-(
case mod_muc_room:set_admin_items(RoomJID, FromJID, [AffItem]) of
332 ok ->
333
:-(
{ok, "Affiliation set successfully"};
334 {error, not_found} ->
335
:-(
?ROOM_NOT_FOUND_RESULT;
336 {error, #xmlel{} = E} ->
337
:-(
format_xml_error(E, Affiliation)
338 end.
339
340 -spec set_role(jid:jid(), binary(), mod_muc:role()) ->
341 {ok | moderator_not_found | room_not_found | not_allowed | cannot_modify, iolist()}.
342 set_role(RoomJID, Nick, Role) ->
343
:-(
case room_moderator(RoomJID) of
344 {ok, ModJID} ->
345
:-(
case mod_muc_room:set_admin_items(RoomJID, ModJID, [role_item(Nick, Role)]) of
346 ok ->
347
:-(
?SET_ROLE_SUCC_RESULT;
348 {error, #xmlel{} = E} ->
349
:-(
format_xml_error(E, Role)
350 end;
351 {error, moderator_not_found} ->
352
:-(
?MODERATOR_NOT_FOUND_RESULT;
353 {error, not_found} ->
354
:-(
?ROOM_NOT_FOUND_RESULT
355 end.
356
357 -spec set_role(jid:jid(), jid:jid(), binary(), mod_muc:role()) ->
358 {ok | moderator_not_found | room_not_found | not_allowed | cannot_modify, iolist()}.
359 set_role(RoomJID, UserJID, Nick, Role) ->
360
:-(
RoleItem = role_item(Nick, Role),
361
:-(
case try_add_role_resource(RoomJID, UserJID, moderator) of
362 {ok, ModJID} ->
363
:-(
case mod_muc_room:set_admin_items(RoomJID, ModJID, [RoleItem]) of
364 ok ->
365
:-(
?SET_ROLE_SUCC_RESULT;
366 {error, #xmlel{} = E} ->
367
:-(
format_xml_error(E, Role)
368 end;
369 {error, not_found} ->
370
:-(
?ROOM_NOT_FOUND_RESULT
371 end.
372
373 -spec enter_room(jid:jid(), jid:jid(), binary() | undefined) -> {ok, iolist()}.
374 enter_room(RoomJID, UserJID, Password) ->
375
:-(
Presence = presence(UserJID, RoomJID, Password),
376
:-(
ejabberd_router:route(UserJID, RoomJID, Presence),
377
:-(
{ok, "Entering room message sent successfully"}.
378
379 -spec exit_room(jid:jid(), jid:jid()) -> {ok, iolist()}.
380 exit_room(RoomJID, UserJID) ->
381
:-(
Presence = exit_room_presence(UserJID, RoomJID),
382
:-(
ejabberd_router:route(UserJID, RoomJID, Presence),
383
:-(
{ok, "Exiting room message sent successfully"}.
384
385 %% Internal
386
387 -spec kick_user_from_room_raw(jid:jid(), jid:jid(), binary(), binary()) -> {ok, iolist()}.
388 kick_user_from_room_raw(RoomJID, ModJID, Nick, ReasonIn) ->
389
:-(
Reason = #xmlel{name = <<"reason">>,
390 children = [#xmlcdata{content = ReasonIn}]
391 },
392
:-(
Item = #xmlel{name = <<"item">>,
393 attrs = [{<<"nick">>, Nick},
394 {<<"role">>, <<"none">>}],
395 children = [ Reason ]
396 },
397
:-(
IQ = iq(<<"set">>, ModJID, RoomJID, [ query(?NS_MUC_ADMIN, [ Item ]) ]),
398
:-(
ejabberd_router:route(ModJID, RoomJID, IQ),
399
:-(
{ok, "Kick message sent successfully"}.
400
401 -spec try_add_role_resource(jid:jid(), jid:jid(), mod_muc:role()) ->
402 {ok, jid:jid()} | {error, not_found}.
403 try_add_role_resource(RoomJID, InUserJID, Role) ->
404
:-(
case mod_muc_room:get_room_users(RoomJID) of
405 {ok, Users} ->
406
:-(
case [UserJID || #user{jid = UserJID, role = Role2} <- Users,
407
:-(
jid:are_bare_equal(InUserJID, UserJID), Role =:= Role2] of
408 [UserJID | _] ->
409
:-(
{ok, UserJID};
410 _ ->
411
:-(
{ok, InUserJID}
412 end;
413 Error ->
414
:-(
Error
415 end.
416
417
:-(
filter_affs_by_type(undefined, Affs) -> Affs;
418
:-(
filter_affs_by_type(Type, Affs) -> [Aff || Aff = {_, T} <- Affs, T =:= Type].
419
420 format_xml_error(#xmlel{name = <<"error">>} = E, Value) ->
421
:-(
case unwrap_xml_error(E) of
422 {<<"406">>, <<"modify">>, <<"not-acceptable">>} ->
423
:-(
Msg = xml:get_path_s(E, [{elem, <<"text">>}, cdata]),
424
:-(
{cannot_modify, Msg};
425 {<<"403">>, <<"auth">>, <<"forbidden">>} ->
426
:-(
{not_allowed, no_permission_msg("affiliation", Value)};
427 {<<"405">>, <<"cancel">>, <<"not-allowed">>} ->
428
:-(
{not_allowed, no_permission_msg("role", Value)}
429 end.
430
431 no_permission_msg(Op, Value) ->
432
:-(
io_lib:format("Given user does not have permission to set the ~p ~s", [Value, Op]).
433
434 unwrap_xml_error(#xmlel{attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
435 children = [#xmlel{name = Condition} | _]}) ->
436
:-(
{Code, Type, Condition}.
437
438 -spec modify_room_config_raw(jid:jid(), room_conf_mod_fun()) -> mod_muc_room:config().
439 modify_room_config_raw(RoomJID, Fun) ->
440
:-(
{ok, Config} = mod_muc_room:get_room_config(RoomJID),
441
:-(
{ok, NewConfig2} = mod_muc_room:change_room_config(RoomJID, Fun(Config)),
442
:-(
NewConfig2.
443
444 -spec to_user_map(mod_muc_room:user(), boolean()) -> user_map().
445 to_user_map(#user{role = Role, nick = Nick}, false = _WithJID) ->
446
:-(
#{jid => null, role => Role, nick => Nick};
447 to_user_map(#user{jid = JID, role = Role, nick = Nick}, true) ->
448
:-(
#{jid => JID, role => Role, nick => Nick}.
449
450 -spec room_to_item(tuple(), jid:lserver(), jid:jid()) -> {true, short_room_desc()} | false.
451 room_to_item({{Name, _}, Pid}, MUCServer, From) ->
452
:-(
case catch gen_fsm_compat:sync_send_all_state_event(
453 Pid, {get_disco_item, From, <<"en">>}, 100) of
454 {item, Desc} ->
455
:-(
Map = room_desc_to_map(Desc),
456
:-(
{true, Map#{jid => jid:to_binary({Name, MUCServer, <<>>})}};
457 _ ->
458
:-(
false
459 end.
460
461 -spec room_desc_to_map(binary()) -> #{title := binary(), private => boolean(),
462 users_number => non_neg_integer()}.
463 room_desc_to_map(Desc) ->
464
:-(
MP = "(\\S+)( \\((private, )?(\\d+)\\))?",
465
:-(
{match, [TitlePos, _, PrivatePos, NumberPos]} = re:run(Desc, MP, [{capture, [1, 2, 3, 4]}]),
466
:-(
Title = binary:part(Desc, TitlePos),
467
:-(
case NumberPos of
468 {-1, 0} ->
469
:-(
#{title => Title};
470 _ ->
471
:-(
Private = {-1, 0} =/= PrivatePos,
472
:-(
Number = binary_to_integer(binary:part(Desc, NumberPos)),
473
:-(
#{title => Title, private => Private, users_number => Number}
474 end.
475
476 -spec verify_room(jid:jid(), jid:jid()) -> ok | {internal | room_not_found, term()}.
477 verify_room(BareRoomJID, OwnerJID) ->
478
:-(
case mod_muc_room:can_access_room(BareRoomJID, OwnerJID) of
479 {ok, true} ->
480
:-(
ok;
481 {ok, false} ->
482
:-(
{internal, "Room is locked"};
483 {error, not_found} ->
484
:-(
?ROOM_NOT_FOUND_RESULT
485 end.
486
487 role_item(Nick, Role) ->
488
:-(
#xmlel{name = <<"item">>, attrs = [{<<"nick">>, Nick}, {<<"role">>, atom_to_binary(Role)}]}.
489
490 affiliation_item(JID, Aff) ->
491
:-(
#xmlel{name = <<"item">>, attrs = [{<<"jid">>, jid:to_binary(JID)},
492 {<<"affiliation">>, atom_to_binary(Aff)}]}.
493
494 iq(Type, Sender, Recipient, Children) when is_binary(Type), is_list(Children) ->
495
:-(
Addresses = address_attributes(Sender, Recipient),
496
:-(
#xmlel{name = <<"iq">>,
497 attrs = Addresses ++ [{<<"type">>, Type}],
498 children = Children
499 }.
500
501 message(Sender, Recipient, Type, Contents) when is_binary(Type), is_list(Contents) ->
502
:-(
Addresses = address_attributes(Sender, Recipient),
503
:-(
Attributes = case Type of
504
:-(
<<>> -> Addresses;
505
:-(
_ -> [{<<"type">>, Type} | Addresses]
506 end,
507
:-(
#xmlel{name = <<"message">>,
508 attrs = Attributes,
509 children = Contents}.
510
511 query(XMLNameSpace, Children)
512 when is_binary(XMLNameSpace), is_list(Children) ->
513
:-(
#xmlel{name = <<"query">>,
514 attrs = [{<<"xmlns">>, XMLNameSpace}],
515 children = Children}.
516
517 presence(Sender, Recipient, Password) ->
518
:-(
Children = case Password of
519
:-(
undefined -> [];
520
:-(
_ -> [#xmlel{name = <<"password">>,
521 children = [#xmlcdata{content = Password}]}]
522 end,
523
:-(
#xmlel{name = <<"presence">>,
524 attrs = address_attributes(Sender, Recipient),
525 children = [#xmlel{name = <<"x">>,
526 attrs = [{<<"xmlns">>, ?NS_MUC}],
527 children = Children}]}.
528
529 exit_room_presence(Sender, Recipient) ->
530
:-(
#xmlel{name = <<"presence">>,
531 attrs = [{<<"type">>, <<"unavailable">>} | address_attributes(Sender, Recipient)],
532 children = [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}]}]}.
533
534 declination(Sender, Recipient) ->
535
:-(
iq(<<"set">>, Sender, Recipient, [data_submission()]).
536
537 data_submission() ->
538
:-(
query(?NS_MUC_OWNER, [mongoose_data_forms:form(#{type => <<"submit">>})]).
539
540 address_attributes(Sender, Recipient) ->
541
:-(
[{<<"from">>, jid:to_binary(Sender)},
542 {<<"to">>, jid:to_binary(Recipient)}].
543
544 room_moderator(RoomJID) ->
545
:-(
case mod_muc_room:get_room_users(RoomJID) of
546 {ok, Users} ->
547
:-(
case [UserJID || #user{jid = UserJID, role = moderator} <- Users] of
548
:-(
[ModJID | _] -> {ok, ModJID};
549
:-(
[] -> {error, moderator_not_found}
550 end;
551 Error ->
552
:-(
Error
553 end.
554
555 room_users_aff(RoomJID) ->
556
:-(
case mod_muc_room:get_room_affiliations(RoomJID) of
557 {ok, Affs} ->
558
:-(
{ok, format_affs(Affs)};
559 {error, Error} ->
560
:-(
{error, Error}
561 end.
562
563 format_affs(AffsMap) ->
564
:-(
lists:map(fun
565
:-(
({K, {V, <<>>}}) -> {K, V};
566
:-(
({K, V}) -> {K, V}
567 end, maps:to_list(AffsMap)).
Line Hits Source