./ct_report/coverage/mongoose_client_api_contacts.COVER.html

1 -module(mongoose_client_api_contacts).
2 -behaviour(cowboy_rest).
3
4 -export([trails/0]).
5 -export([init/2]).
6 -export([content_types_provided/2]).
7 -export([content_types_accepted/2]).
8 -export([is_authorized/2]).
9 -export([allowed_methods/2]).
10
11 -export([forbidden_request/2]).
12
13 -export([to_json/2]).
14 -export([from_json/2]).
15 -export([delete_resource/2]).
16
17 -ignore_xref([from_json/2, to_json/2, trails/0, forbidden_request/2]).
18
19 -include("mongoose.hrl").
20 -include("jlib.hrl").
21 -include_lib("exml/include/exml.hrl").
22
23 trails() ->
24 80 mongoose_client_api_contacts_doc:trails().
25
26 init(Req, Opts) ->
27 30 mongoose_client_api:init(Req, Opts).
28
29 is_authorized(Req, State) ->
30 30 mongoose_client_api:is_authorized(Req, State).
31
32 content_types_provided(Req, State) ->
33 28 {[
34 {{<<"application">>, <<"json">>, '*'}, to_json}
35 ], Req, State}.
36
37 content_types_accepted(Req, State) ->
38 13 {[
39 {{<<"application">>, <<"json">>, '*'}, from_json}
40 ], Req, State}.
41
42 allowed_methods(Req, State) ->
43 30 {[<<"OPTIONS">>, <<"GET">>, <<"POST">>, <<"PUT">>, <<"DELETE">>],
44 Req, State}.
45
46 forbidden_request(Req, State) ->
47
:-(
Req1 = cowboy_req:reply(403, Req),
48
:-(
{stop, Req1, State}.
49
50 to_json(Req, #{jid := Caller} = State) ->
51 12 CJid = jid:to_binary(Caller),
52 12 Method = cowboy_req:method(Req),
53 12 Jid = cowboy_req:binding(jid, Req),
54 12 case Jid of
55 undefined ->
56 11 {ok, Res} = handle_request(Method, Jid, undefined, CJid, State),
57 11 {jiffy:encode(lists:flatten([Res])), Req, State};
58 _ ->
59 1 Req2 = cowboy_req:reply(404, Req),
60 1 {stop, Req2, State}
61 end.
62
63
64 from_json(Req, #{jid := Caller} = State) ->
65 13 CJid = jid:to_binary(Caller),
66 13 Method = cowboy_req:method(Req),
67 13 {ok, Body, Req1} = cowboy_req:read_body(Req),
68 13 case mongoose_client_api:json_to_map(Body) of
69 {ok, JSONData} ->
70 13 Jid = case maps:get(<<"jid">>, JSONData, undefined) of
71 4 undefined -> cowboy_req:binding(jid, Req1);
72 9 J when is_binary(J) -> J;
73
:-(
_ -> undefined
74 end,
75 13 Action = maps:get(<<"action">>, JSONData, undefined),
76 13 handle_request_and_respond(Method, Jid, Action, CJid, Req1, State);
77 _ ->
78
:-(
mongoose_client_api:bad_request(Req1, State)
79 end.
80
81 %% @doc Called for a method of type "DELETE"
82 delete_resource(Req, #{jid := Caller} = State) ->
83 3 CJid = jid:to_binary(Caller),
84 3 Jid = cowboy_req:binding(jid, Req),
85 3 case Jid of
86 undefined ->
87 2 handle_multiple_deletion(CJid, get_requested_contacts(Req), Req, State);
88 _ ->
89 1 handle_single_deletion(CJid, Jid, Req, State)
90 end.
91
92 handle_multiple_deletion(_, undefined, Req, State) ->
93
:-(
mongoose_client_api:bad_request(Req, State);
94 handle_multiple_deletion(CJid, ToDelete, Req, State) ->
95 2 case handle_request(<<"DELETE">>, ToDelete, undefined, CJid, State) of
96 {ok, NotDeleted} ->
97 2 RespBody = #{not_deleted => NotDeleted},
98 2 Req2 = cowboy_req:set_resp_body(jiffy:encode(RespBody), Req),
99 2 Req3 = cowboy_req:set_resp_header(<<"content-type">>, <<"application/json">>, Req2),
100 2 {true, Req3, State};
101 Other ->
102
:-(
serve_failure(Other, Req, State)
103 end.
104
105 handle_single_deletion(_, undefined, Req, State) ->
106
:-(
mongoose_client_api:bad_request(Req, State);
107 handle_single_deletion(CJid, ToDelete, Req, State) ->
108 1 case handle_request(<<"DELETE">>, ToDelete, undefined, CJid, State) of
109 ok ->
110 1 {true, Req, State};
111 Other ->
112
:-(
serve_failure(Other, Req, State)
113 end.
114
115 handle_request_and_respond(_, undefined, _, _, Req, State) ->
116
:-(
mongoose_client_api:bad_request(Req, State);
117 handle_request_and_respond(Method, Jid, Action, CJid, Req, State) ->
118 13 case handle_request(Method, to_binary(Jid), Action, CJid, State) of
119 ok ->
120 11 {true, Req, State};
121 not_implemented ->
122 1 Req2 = cowboy_req:reply(501, Req),
123 1 {stop, Req2, State};
124 not_found ->
125 1 Req2 = cowboy_req:reply(404, Req),
126 1 {stop, Req2, State}
127 end.
128
129 serve_failure(not_implemented, Req, State) ->
130
:-(
Req2 = cowboy_req:reply(501, Req),
131
:-(
{stop, Req2, State};
132 serve_failure(not_found, Req, State) ->
133
:-(
Req2 = cowboy_req:reply(404, Req),
134
:-(
{stop, Req2, State};
135 serve_failure({error, ErrorType, Msg}, Req, State) ->
136
:-(
?LOG_ERROR(#{what => api_contacts_error,
137 text => <<"Error while serving http request. Return code 500">>,
138
:-(
error_type => ErrorType, msg => Msg, req => Req}),
139
:-(
Req2 = cowboy_req:reply(500, Req),
140
:-(
{stop, Req2, State}.
141
142 get_requested_contacts(Req) ->
143 2 Body = get_whole_body(Req, <<"">>),
144 2 case mongoose_client_api:json_to_map(Body) of
145 {ok, #{<<"to_delete">> := ResultJids}} when is_list(ResultJids) ->
146 2 case [X || X <- ResultJids, is_binary(X)] =:= ResultJids of
147 true ->
148 2 ResultJids;
149 false ->
150
:-(
undefined
151 end;
152 _ ->
153
:-(
undefined
154 end.
155
156 get_whole_body(Req, Acc) ->
157 2 case cowboy_req:read_body(Req) of
158 {ok, Data, _Req2} ->
159 2 <<Data/binary, Acc/binary>>;
160 {more, Data, Req2} ->
161
:-(
get_whole_body(Req2, <<Data/binary, Acc/binary>>)
162 end.
163
164 handle_request(<<"GET">>, undefined, undefined, CJid, _State) ->
165 11 mongoose_commands:execute(CJid, list_contacts, #{caller => CJid});
166 handle_request(<<"POST">>, Jid, undefined, CJid, _State) ->
167 9 mongoose_commands:execute(CJid, add_contact, #{caller => CJid,
168 jid => Jid});
169 handle_request(<<"DELETE">>, Jids, _Action, CJid, _State) when is_list(Jids) ->
170 2 mongoose_commands:execute(CJid, delete_contacts, #{caller => CJid,
171 jids => Jids});
172 handle_request(Method, Jid, Action, CJid, #{jid := CallerJid, creds := Creds}) ->
173 5 HostType = mongoose_credentials:host_type(Creds),
174 5 case contact_exists(HostType, CallerJid, jid:from_binary(Jid)) of
175 true ->
176 4 handle_contact_request(Method, Jid, Action, CJid);
177 1 false -> not_found
178 end.
179
180 handle_contact_request(<<"PUT">>, Jid, <<"invite">>, CJid) ->
181 1 mongoose_commands:execute(CJid, subscription, #{caller => CJid,
182 jid => Jid, action => atom_to_binary(subscribe, latin1)});
183 handle_contact_request(<<"PUT">>, Jid, <<"accept">>, CJid) ->
184 1 mongoose_commands:execute(CJid, subscription, #{caller => CJid,
185 jid => Jid, action => atom_to_binary(subscribed, latin1)});
186 handle_contact_request(<<"DELETE">>, Jid, undefined, CJid) ->
187 1 mongoose_commands:execute(CJid, delete_contact, #{caller => CJid,
188 jid => Jid});
189 handle_contact_request(_, _, _, _) ->
190 1 not_implemented.
191
192 to_binary(S) when is_binary(S) ->
193 13 S;
194 to_binary(S) ->
195
:-(
list_to_binary(S).
196
197 -spec contact_exists(mongooseim:host_type(), jid:jid(), jid:jid() | error) -> boolean().
198
:-(
contact_exists(_, _, error) -> false;
199 contact_exists(HostType, CallerJid, Jid) ->
200 5 LJid = jid:to_lower(Jid),
201 5 Res = mod_roster:get_roster_entry(HostType, CallerJid, LJid, short),
202 5 Res =/= does_not_exist andalso Res =/= error.
Line Hits Source