./ct_report/coverage/mongoose_client_api_rooms.COVER.html

1 -module(mongoose_client_api_rooms).
2
3 -behaviour(mongoose_client_api).
4 -export([routes/0]).
5
6 -behaviour(cowboy_rest).
7 -export([trails/0,
8 init/2,
9 is_authorized/2,
10 content_types_provided/2,
11 content_types_accepted/2,
12 allowed_methods/2,
13 to_json/2,
14 from_json/2]).
15
16 %% Used by mongoose_client_api_rooms_*
17 -export([get_room_jid/3,
18 get_room_name/1,
19 get_room_subject/1]).
20
21 -ignore_xref([from_json/2, to_json/2, trails/0]).
22
23 -import(mongoose_client_api, [parse_body/1, try_handle_request/3, throw_error/2]).
24
25 -type req() :: cowboy_req:req().
26 -type state() :: map().
27
28 -include("jlib.hrl").
29
30 -spec routes() -> mongoose_http_handler:routes().
31 routes() ->
32 4 [{"/rooms/[:id]", ?MODULE, #{}}].
33
34 trails() ->
35 4 mongoose_client_api_rooms_doc:trails().
36
37 -spec init(req(), state()) -> {cowboy_rest, req(), state()}.
38 init(Req, Opts) ->
39
:-(
mongoose_client_api:init(Req, Opts).
40
41 -spec is_authorized(req(), state()) -> {true | {false, iodata()}, req(), state()}.
42 is_authorized(Req, State) ->
43
:-(
mongoose_client_api:is_authorized(Req, State).
44
45 -spec content_types_provided(req(), state()) ->
46 {[{{binary(), binary(), '*'}, atom()}], req(), state()}.
47 content_types_provided(Req, State) ->
48
:-(
{[
49 {{<<"application">>, <<"json">>, '*'}, to_json}
50 ], Req, State}.
51
52 -spec content_types_accepted(req(), state()) ->
53 {[{{binary(), binary(), '*'}, atom()}], req(), state()}.
54 content_types_accepted(Req, State) ->
55
:-(
{[
56 {{<<"application">>, <<"json">>, '*'}, from_json}
57 ], Req, State}.
58
59 -spec allowed_methods(req(), state()) -> {[binary()], req(), state()}.
60 allowed_methods(Req, State) ->
61
:-(
{[<<"OPTIONS">>, <<"GET">>, <<"POST">>, <<"PUT">>], Req, State}.
62
63 %% @doc Called for a method of type "GET"
64 -spec to_json(req(), state()) -> {iodata() | stop, req(), state()}.
65 to_json(Req, State) ->
66
:-(
try_handle_request(Req, State, fun handle_get/2).
67
68 %% @doc Called for a method of type "POST" and "PUT"
69 -spec from_json(req(), state()) -> {stop, req(), state()}.
70 from_json(Req, State) ->
71
:-(
F = case cowboy_req:method(Req) of
72
:-(
<<"POST">> -> fun handle_post/2;
73
:-(
<<"PUT">> -> fun handle_put/2
74 end,
75
:-(
try_handle_request(Req, State, F).
76
77 %% Internal functions
78
79 handle_get(Req, State = #{jid := UserJid}) ->
80
:-(
Bindings = cowboy_req:bindings(Req),
81
:-(
case get_room_jid(Bindings, State, optional) of
82 undefined ->
83
:-(
{ok, Rooms} = mod_muc_light_api:get_user_rooms(UserJid),
84
:-(
{jiffy:encode(lists:flatmap(fun room_us_to_json/1, Rooms)), Req, State};
85 RoomJid ->
86
:-(
case mod_muc_light_api:get_room_info(RoomJid, UserJid) of
87 {ok, Info} ->
88
:-(
{jiffy:encode(room_info_to_json(Info)), Req, State};
89 {room_not_found, Msg} ->
90
:-(
throw_error(not_found, Msg);
91 {not_room_member, Msg} ->
92
:-(
throw_error(denied, Msg)
93 end
94 end.
95
96 handle_post(Req, State = #{jid := UserJid}) ->
97
:-(
MUCLightDomain = muc_light_domain(State),
98
:-(
Args = parse_body(Req),
99
:-(
Name = get_room_name(Args),
100
:-(
Subject = get_room_subject(Args),
101
:-(
Config = #{<<"roomname">> => Name, <<"subject">> => Subject},
102
:-(
{ok, #{jid := RoomJid}} = mod_muc_light_api:create_room(MUCLightDomain, UserJid, Config),
103
:-(
room_created(Req, State, RoomJid).
104
105 handle_put(Req, State = #{jid := UserJid}) ->
106
:-(
Bindings = cowboy_req:bindings(Req),
107
:-(
#jid{luser = RoomId, lserver = MUCLightDomain} = get_room_jid(Bindings, State, required),
108
:-(
Args = parse_body(Req),
109
:-(
Name = get_room_name(Args),
110
:-(
Subject = get_room_subject(Args),
111
:-(
Config = #{<<"roomname">> => Name, <<"subject">> => Subject},
112
:-(
case mod_muc_light_api:create_room(MUCLightDomain, RoomId, UserJid, Config) of
113 {ok, #{jid := RoomJid}} ->
114
:-(
room_created(Req, State, RoomJid);
115 {already_exists, Msg} ->
116
:-(
throw_error(denied, Msg)
117 end.
118
119 room_created(Req, State, RoomJid) ->
120
:-(
RespBody = #{<<"id">> => RoomJid#jid.luser},
121
:-(
Req2 = cowboy_req:set_resp_body(jiffy:encode(RespBody), Req),
122
:-(
Req3 = cowboy_req:reply(201, Req2),
123
:-(
{stop, Req3, State}.
124
125 -spec room_us_to_json(jid:simple_bare_jid()) -> [jiffy:json_value()].
126 room_us_to_json({RoomU, RoomS}) ->
127
:-(
#jid{luser = RoomId} = RoomJid = jid:make_noprep(RoomU, RoomS, <<>>),
128
:-(
case mod_muc_light_api:get_room_info(RoomJid) of
129 {ok, Info} ->
130
:-(
NS = room_name_and_subject(Info),
131
:-(
[NS#{id => RoomId}];
132 {room_not_found, _} ->
133
:-(
[] % room was removed after listing rooms, but before this query
134 end.
135
136 -spec room_info_to_json(mod_muc_light_api:room()) -> jiffy:json_value().
137 room_info_to_json(Info = #{aff_users := AffUsers}) ->
138
:-(
NS = room_name_and_subject(Info),
139
:-(
NS#{participants => lists:map(fun user_to_json/1, AffUsers)}.
140
141 room_name_and_subject(#{options := #{<<"roomname">> := Name, <<"subject">> := Subject}}) ->
142
:-(
#{name => Name, subject => Subject}.
143
144 user_to_json({UserServer, Role}) ->
145
:-(
#{user => jid:to_binary(UserServer),
146 role => Role}.
147
148 get_room_jid(#{id := IdOrJid}, State, _) ->
149
:-(
MUCLightDomain = muc_light_domain(State),
150
:-(
case jid:nodeprep(IdOrJid) of
151 error ->
152
:-(
case jid:from_binary(IdOrJid) of
153 error ->
154
:-(
throw_error(bad_request, <<"Invalid room ID">>);
155 #jid{lserver = MUCLightDomain} = Jid ->
156
:-(
Jid;
157 #jid{} ->
158
:-(
throw_error(bad_request, <<"Invalid MUC Light domain">>)
159 end;
160 RoomId when RoomId =/= <<>> ->
161
:-(
jid:make_noprep(RoomId, MUCLightDomain, <<>>)
162 end;
163
:-(
get_room_jid(#{}, _State, required) -> throw_error(bad_request, <<"Missing room ID">>);
164
:-(
get_room_jid(#{}, _State, optional) -> undefined.
165
166 muc_light_domain(#{creds := Creds}) ->
167
:-(
HostType = mongoose_credentials:host_type(Creds),
168
:-(
LServer = mongoose_credentials:lserver(Creds),
169
:-(
try
170
:-(
mod_muc_light_utils:server_host_to_muc_host(HostType, LServer)
171 catch
172
:-(
_:_ -> throw_error(not_found, <<"MUC Light server not found">>)
173 end.
174
175
:-(
get_room_name(#{name := Name}) -> Name;
176
:-(
get_room_name(#{}) -> throw_error(bad_request, <<"Missing room name">>).
177
178
:-(
get_room_subject(#{subject := Subject}) -> Subject;
179
:-(
get_room_subject(#{}) -> throw_error(bad_request, <<"Missing room subject">>).
Line Hits Source