./ct_report/coverage/mongoose_admin_api_contacts.COVER.html

1 -module(mongoose_admin_api_contacts).
2
3 -behaviour(mongoose_admin_api).
4 -export([routes/1]).
5
6 -behaviour(cowboy_rest).
7 -export([init/2,
8 is_authorized/2,
9 content_types_provided/2,
10 content_types_accepted/2,
11 allowed_methods/2,
12 to_json/2,
13 from_json/2,
14 delete_resource/2]).
15
16 -ignore_xref([to_json/2, from_json/2]).
17
18 -import(mongoose_admin_api, [parse_body/1, try_handle_request/3, throw_error/2]).
19
20 -type req() :: cowboy_req:req().
21 -type state() :: mongoose_admin_api:state().
22
23 -spec routes(state()) -> mongoose_http_handler:routes().
24 routes(State) ->
25 4 [{"/contacts/:user/[:contact]", ?MODULE, State},
26 {"/contacts/:user/:contact/manage", ?MODULE, State#{suffix => manage}}].
27
28 -spec init(req(), state()) -> {cowboy_rest, req(), state()}.
29 init(Req, State) ->
30
:-(
mongoose_admin_api:init(Req, State).
31
32 -spec is_authorized(req(), state()) -> {true | {false, iodata()}, req(), state()}.
33 is_authorized(Req, State) ->
34
:-(
mongoose_admin_api:is_authorized(Req, State).
35
36 -spec content_types_provided(req(), state()) ->
37 {[{{binary(), binary(), '*'}, atom()}], req(), state()}.
38 content_types_provided(Req, State) ->
39
:-(
{[
40 {{<<"application">>, <<"json">>, '*'}, to_json}
41 ], Req, State}.
42
43 -spec content_types_accepted(req(), state()) ->
44 {[{{binary(), binary(), '*'}, atom()}], req(), state()}.
45 content_types_accepted(Req, State) ->
46
:-(
{[
47 {{<<"application">>, <<"json">>, '*'}, from_json}
48 ], Req, State}.
49
50 -spec allowed_methods(req(), state()) -> {[binary()], req(), state()}.
51 allowed_methods(Req, State) ->
52
:-(
{[<<"OPTIONS">>, <<"GET">>, <<"POST">>, <<"PUT">>, <<"DELETE">>], Req, State}.
53
54 %% @doc Called for a method of type "GET"
55 -spec to_json(req(), state()) -> {iodata() | stop, req(), state()}.
56 to_json(Req, State) ->
57
:-(
try_handle_request(Req, State, fun handle_get/2).
58
59 %% @doc Called for a method of type "POST" or "PUT"
60 -spec from_json(req(), state()) -> {true | stop, req(), state()}.
61 from_json(Req, State) ->
62
:-(
F = case cowboy_req:method(Req) of
63
:-(
<<"POST">> -> fun handle_post/2;
64
:-(
<<"PUT">> -> fun handle_put/2
65 end,
66
:-(
try_handle_request(Req, State, F).
67
68 %% @doc Called for a method of type "DELETE"
69 -spec delete_resource(req(), state()) -> {true | stop, req(), state()}.
70 delete_resource(Req, State) ->
71
:-(
try_handle_request(Req, State, fun handle_delete/2).
72
73 %% Internal functions
74
75 handle_get(Req, State) ->
76
:-(
Bindings = cowboy_req:bindings(Req),
77
:-(
UserJid = get_user_jid(Bindings),
78
:-(
case mod_roster_api:list_contacts(UserJid) of
79 {ok, Rosters} ->
80
:-(
{jiffy:encode(lists:map(fun roster_info/1, Rosters)), Req, State};
81 {unknown_domain, Reason} ->
82
:-(
throw_error(not_found, Reason)
83 end.
84
85 handle_post(Req, State) ->
86
:-(
Bindings = cowboy_req:bindings(Req),
87
:-(
UserJid = get_user_jid(Bindings),
88
:-(
Args = parse_body(Req),
89
:-(
ContactJid = get_jid(Args),
90
:-(
case mod_roster_api:add_contact(UserJid, ContactJid, <<>>, []) of
91 {unknown_domain, Reason} ->
92
:-(
throw_error(not_found, Reason);
93 {user_not_exist, Reason} ->
94
:-(
throw_error(not_found, Reason);
95 {ok, _} ->
96
:-(
{true, Req, State}
97 end.
98
99 handle_put(Req, State) ->
100
:-(
Bindings = cowboy_req:bindings(Req),
101
:-(
UserJid = get_user_jid(Bindings),
102
:-(
ContactJid = get_contact_jid(Bindings),
103
:-(
Args = parse_body(Req),
104
:-(
Action = get_action(Args, State),
105
:-(
case perform_action(UserJid, ContactJid, Action, State) of
106 {unknown_domain, Reason} ->
107
:-(
throw_error(not_found, Reason);
108 {user_not_exist, Reason} ->
109
:-(
throw_error(not_found, Reason);
110 {contact_not_found, Reason} ->
111
:-(
throw_error(not_found, Reason);
112 {ok, _} ->
113
:-(
{true, Req, State}
114 end.
115
116 handle_delete(Req, State) ->
117
:-(
Bindings = cowboy_req:bindings(Req),
118
:-(
UserJid = get_user_jid(Bindings),
119
:-(
ContactJid = get_contact_jid(Bindings),
120
:-(
case mod_roster_api:delete_contact(UserJid, ContactJid) of
121 {contact_not_found, Reason} ->
122
:-(
throw_error(not_found, Reason);
123 {ok, _} ->
124
:-(
{true, Req, State}
125 end.
126
127 perform_action(UserJid, ContactJid, Action, #{suffix := manage}) ->
128
:-(
mod_roster_api:set_mutual_subscription(UserJid, ContactJid, Action);
129 perform_action(UserJid, ContactJid, Action, #{}) ->
130
:-(
mod_roster_api:subscription(UserJid, ContactJid, Action).
131
132 -spec roster_info(mod_roster:roster()) -> jiffy:json_value(). %% returns jiffy:json_object()
133 roster_info(Roster) ->
134
:-(
#{jid := Jid, subscription := Sub, ask := Ask} = mod_roster:item_to_map(Roster),
135
:-(
#{jid => jid:to_binary(Jid), subscription => Sub, ask => Ask}.
136
137 get_jid(#{jid := JidBin}) ->
138
:-(
case jid:from_binary(JidBin) of
139
:-(
error -> throw_error(bad_request, <<"Invalid JID">>);
140
:-(
Jid -> Jid
141 end;
142 get_jid(#{}) ->
143
:-(
throw_error(bad_request, <<"Missing JID">>).
144
145 get_user_jid(#{user := User}) ->
146
:-(
case jid:from_binary(User) of
147
:-(
error -> throw_error(bad_request, <<"Invalid user JID">>);
148
:-(
Jid -> Jid
149 end.
150
151 get_contact_jid(#{contact := Contact}) ->
152
:-(
case jid:from_binary(Contact) of
153
:-(
error -> throw_error(bad_request, <<"Invalid contact JID">>);
154
:-(
Jid -> Jid
155 end;
156 get_contact_jid(#{}) ->
157
:-(
throw_error(bad_request, <<"Missing contact JID">>).
158
159 get_action(#{action := ActionBin}, State) ->
160
:-(
decode_action(ActionBin, maps:get(suffix, State, no_suffix));
161 get_action(#{}, _State) ->
162
:-(
throw_error(bad_request, <<"Missing action">>).
163
164
:-(
decode_action(<<"subscribe">>, no_suffix) -> subscribe;
165
:-(
decode_action(<<"subscribed">>, no_suffix) -> subscribed;
166
:-(
decode_action(<<"connect">>, manage) -> connect;
167
:-(
decode_action(<<"disconnect">>, manage) -> disconnect;
168
:-(
decode_action(_, _) -> throw_error(bad_request, <<"Invalid action">>).
Line Hits Source