./ct_report/coverage/mod_vcard_api.COVER.html

1 %% @doc Provide an interface for frontends (like graphql or ctl) to manage vcard.
2 -module(mod_vcard_api).
3
4 -include("mongoose.hrl").
5 -include("jlib.hrl").
6 -include("mod_vcard.hrl").
7
8 -type vcard_map() :: #{binary() => vcard_subelement_binary() | vcard_subelement_map()}.
9 -type vcard_subelement_binary() :: binary() | [{ok, binary()}].
10 -type vcard_subelement_map() :: #{binary() => binary() | [{ok, binary()}]}.
11
12 -export([set_vcard/2,
13 get_vcard/1]).
14
15 -spec set_vcard(jid:jid(), vcard_map()) ->
16 {ok, vcard_map()} | {user_not_found, string()} | {internal, string()} | {vcard_not_found, string()}.
17 set_vcard(#jid{luser = LUser, lserver = LServer} = UserJID, Vcard) ->
18
:-(
case check_user(UserJID) of
19 {ok, HostType} ->
20
:-(
case set_vcard(HostType, UserJID, Vcard) of
21 ok ->
22
:-(
get_vcard_from_db(HostType, LUser, LServer);
23 _ ->
24
:-(
{internal, "Internal server error"}
25 end;
26 Error ->
27
:-(
Error
28 end.
29
30 -spec get_vcard(jid:jid()) ->
31 {ok, vcard_map()} | {user_not_found, string()} | {internal, string()} | {vcard_not_found, string()}
32 | {vcard_not_configured_error, string()}.
33 get_vcard(#jid{luser = LUser, lserver = LServer} = UserJID) ->
34 % check if mod_vcard is loaded is needed in user's get_vcard command, when user variable is not passed
35
:-(
case check_user(UserJID) of
36 {ok, HostType} ->
37
:-(
case gen_mod:is_loaded(HostType, mod_vcard) of
38 true ->
39
:-(
get_vcard_from_db(HostType, LUser, LServer);
40 false ->
41
:-(
{vcard_not_configured_error, "Mod_vcard is not loaded for this host"}
42 end;
43 Error ->
44
:-(
Error
45 end.
46
47 set_vcard(HostType, UserJID, Vcard) ->
48
:-(
mod_vcard:unsafe_set_vcard(HostType, UserJID, transform_from_map(Vcard)).
49
50 get_vcard_from_db(HostType, LUser, LServer) ->
51
:-(
ItemNotFoundError = mongoose_xmpp_errors:item_not_found(),
52
:-(
case mod_vcard_backend:get_vcard(HostType, LUser, LServer) of
53 {ok, Result} ->
54
:-(
[#xmlel{children = VcardData}] = Result,
55
:-(
{ok, to_map_format(VcardData)};
56 {error, ItemNotFoundError} ->
57
:-(
{vcard_not_found, "Vcard for user not found"};
58 _ ->
59
:-(
{internal, "Internal server error"}
60 end.
61
62 -spec check_user(jid:jid()) -> {ok, mongooseim:host_type()} | {user_not_found, binary()}.
63 check_user(JID = #jid{lserver = LServer}) ->
64
:-(
case mongoose_domain_api:get_domain_host_type(LServer) of
65 {ok, HostType} ->
66
:-(
case ejabberd_auth:does_user_exist(HostType, JID, stored) of
67
:-(
true -> {ok, HostType};
68
:-(
false -> {user_not_found, <<"Given user does not exist">>}
69 end;
70 {error, not_found} ->
71
:-(
{user_not_found, <<"User's domain does not exist">>}
72 end.
73
74 transform_from_map(Vcard) ->
75
:-(
#xmlel{name = <<"vCard">>,
76 attrs = [{<<"xmlns">>, <<"vcard-temp">>}],
77 children = lists:foldl(fun({Name, Value}, Acc) ->
78
:-(
Acc ++ transform_field_and_value(Name, Value)
79 end, [], maps:to_list(Vcard))}.
80
81 construct_xmlel(Name, Children) when is_list(Children)->
82
:-(
[#xmlel{name = Name,
83 attrs = [],
84 children = Children}].
85
86 transform_field_and_value(_Name, null) ->
87
:-(
[];
88 transform_field_and_value(Name, Value) when is_list(Value) ->
89
:-(
lists:foldl(fun(Element, Acc) ->
90
:-(
Acc ++ transform_field_and_value(Name, Element)
91 end, [], Value);
92 transform_field_and_value(Name, Value) when is_map(Value) ->
93
:-(
construct_xmlel(from_map_to_xml(Name), process_child_map(Value));
94 transform_field_and_value(Name, Value) ->
95
:-(
construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Value}]).
96
97 transform_subfield_and_value(_Name, null) ->
98
:-(
[];
99 transform_subfield_and_value(<<"vcard">>, Value) ->
100
:-(
[transform_from_map(Value)];
101 transform_subfield_and_value(<<"tags">>, TagsList) ->
102
:-(
lists:foldl(fun(Tag, Acc) ->
103
:-(
Acc ++ construct_xmlel(Tag, [])
104 end, [], TagsList);
105 transform_subfield_and_value(Name, Value) when is_list(Value) ->
106
:-(
lists:foldl(fun(Element, Acc) ->
107
:-(
Acc ++ construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Element}])
108 end, [], Value);
109 transform_subfield_and_value(Name, Value) ->
110
:-(
construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Value}]).
111
112 process_child_map(Value) ->
113
:-(
lists:foldl(fun({Name, SubfieldValue}, Acc) ->
114
:-(
Acc ++ transform_subfield_and_value(Name, SubfieldValue)
115 end, [], maps:to_list(Value)).
116
117
:-(
from_map_to_xml(<<"formattedName">>) -> <<"FN">>;
118
:-(
from_map_to_xml(<<"nameComponents">>) -> <<"N">>;
119
:-(
from_map_to_xml(<<"birthday">>) -> <<"BDAY">>;
120
:-(
from_map_to_xml(<<"address">>) -> <<"ADR">>;
121
:-(
from_map_to_xml(<<"telephone">>) -> <<"TEL">>;
122
:-(
from_map_to_xml(<<"timeZone">>) -> <<"TZ">>;
123
:-(
from_map_to_xml(<<"sortString">>) -> <<"SOR">>;
124
:-(
from_map_to_xml(<<"givenName">>) -> <<"GIVEN">>;
125
:-(
from_map_to_xml(<<"middleName">>) -> <<"MIDDLE">>;
126
:-(
from_map_to_xml(<<"credential">>) -> <<"CRED">>;
127
:-(
from_map_to_xml(<<"country">>) -> <<"CTRY">>;
128
:-(
from_map_to_xml(<<"binValue">>) -> <<"BINVAL">>;
129
:-(
from_map_to_xml(<<"extValue">>) -> <<"EXTVAL">>;
130
:-(
from_map_to_xml(Name) -> list_to_binary(string:to_upper(binary_to_list(Name))).
131
132 to_map_format(Vcard) ->
133
:-(
lists:foldl(fun(#xmlel{name = Name, children = Value}, Acc) ->
134
:-(
maps:merge(Acc, transform_from_xml(Name, Value, Acc))
135 end, #{}, Vcard).
136
137 transform_from_xml(<<"FN">>, [{_, Value}], _) ->
138
:-(
#{<<"formattedName">> => Value};
139 transform_from_xml(<<"N">>, Value, _) ->
140
:-(
#{<<"nameComponents">> => lists:foldl(fun name_components_process/2, #{}, Value)};
141 transform_from_xml(<<"NICKNAME">>, Value, Acc) ->
142
:-(
simple_process(<<"nickname">>, Value, Acc);
143 transform_from_xml(<<"PHOTO">>, Value, Acc) ->
144
:-(
complex_process(<<"photo">>, Value, Acc, fun image_components_process/2);
145 transform_from_xml(<<"BDAY">>, Value, Acc) ->
146
:-(
simple_process(<<"birthday">>, Value, Acc);
147 transform_from_xml(<<"ADR">>, Value, Acc) ->
148
:-(
complex_process(<<"address">>, Value, Acc, fun address_components_process/2);
149 transform_from_xml(<<"LABEL">>, Value, Acc) ->
150
:-(
complex_process(<<"label">>, Value, Acc, fun label_components_process/2);
151 transform_from_xml(<<"TEL">>, Value, Acc) ->
152
:-(
complex_process(<<"telephone">>, Value, Acc, fun telephone_components_process/2);
153 transform_from_xml(<<"EMAIL">>, Value, Acc) ->
154
:-(
complex_process(<<"email">>, Value, Acc, fun email_components_process/2);
155 transform_from_xml(<<"JABBERID">>, Value, Acc) ->
156
:-(
simple_process(<<"jabberId">>, Value, Acc);
157 transform_from_xml(<<"MAILER">>, Value, Acc) ->
158
:-(
simple_process(<<"mailer">>, Value, Acc);
159 transform_from_xml(<<"TZ">>, Value, Acc) ->
160
:-(
simple_process(<<"timeZone">>, Value, Acc);
161 transform_from_xml(<<"GEO">>, Value, Acc) ->
162
:-(
complex_process(<<"geo">>, Value, Acc, fun geo_components_process/2);
163 transform_from_xml(<<"TITLE">>, Value, Acc) ->
164
:-(
simple_process(<<"title">>, Value, Acc);
165 transform_from_xml(<<"ROLE">>, Value, Acc) ->
166
:-(
simple_process(<<"role">>, Value, Acc);
167 transform_from_xml(<<"LOGO">>, Value, Acc) ->
168
:-(
complex_process(<<"logo">>, Value, Acc, fun image_components_process/2);
169 transform_from_xml(<<"AGENT">>, Value, Acc) ->
170
:-(
complex_process(<<"agent">>, Value, Acc, fun agent_components_process/2);
171 transform_from_xml(<<"ORG">>, Value, Acc) ->
172
:-(
complex_process(<<"org">>, Value, Acc, fun org_components_process/2);
173 transform_from_xml(<<"CATEGORIES">>, Value, Acc) ->
174
:-(
complex_process(<<"categories">>, Value, Acc, fun categories_components_process/2);
175 transform_from_xml(<<"NOTE">>, Value, Acc) ->
176
:-(
simple_process(<<"note">>, Value, Acc);
177 transform_from_xml(<<"PRODID">>, Value, Acc) ->
178
:-(
simple_process(<<"prodId">>, Value, Acc);
179 transform_from_xml(<<"REV">>, Value, Acc) ->
180
:-(
simple_process(<<"rev">>, Value, Acc);
181 transform_from_xml(<<"SOR">>, Value, Acc) ->
182
:-(
simple_process(<<"sortString">>, Value, Acc);
183 transform_from_xml(<<"SOUND">>, Value, Acc) ->
184
:-(
complex_process(<<"sound">>, Value, Acc, fun sound_components_process/2);
185 transform_from_xml(<<"UID">>, Value, Acc) ->
186
:-(
simple_process(<<"uid">>, Value, Acc);
187 transform_from_xml(<<"URL">>, Value, Acc) ->
188
:-(
simple_process(<<"url">>, Value, Acc);
189 transform_from_xml(<<"DESC">>, Value, Acc) ->
190
:-(
simple_process(<<"desc">>, Value, Acc);
191 transform_from_xml(<<"CLASS">>, Value, Acc) ->
192
:-(
complex_process(<<"class">>, Value, Acc, fun class_components_process/2);
193 transform_from_xml(<<"KEY">>, Value, Acc) ->
194
:-(
complex_process(<<"key">>, Value, Acc, fun key_components_process/2);
195 transform_from_xml(_, _, _) ->
196
:-(
#{}.
197
198 process_value([{_, Value}]) ->
199
:-(
Value;
200 process_value(_) ->
201
:-(
null.
202
203 simple_process(Name, [{_, Value}], Acc) ->
204
:-(
List = maps:get(Name, Acc, []),
205
:-(
#{Name => List ++ [{ok, Value}]};
206 simple_process(_, _, _) ->
207
:-(
#{}.
208
209 complex_process(Name, Value, Acc, Fun) ->
210
:-(
List = maps:get(Name, Acc, []),
211
:-(
#{Name => List ++ [{ok, lists:foldl(fun(Element, Accumulator) ->
212
:-(
Fun(Element, Accumulator)
213 end, #{}, Value)}]}.
214
215 name_components_process(#xmlel{name = <<"FAMILY">>, children = Value}, Acc) ->
216
:-(
maps:put(<<"family">>, process_value(Value), Acc);
217 name_components_process(#xmlel{name = <<"GIVEN">>, children = Value}, Acc) ->
218
:-(
maps:put(<<"givenName">>, process_value(Value), Acc);
219 name_components_process(#xmlel{name = <<"MIDDLE">>, children = Value}, Acc) ->
220
:-(
maps:put(<<"middleName">>, process_value(Value), Acc);
221 name_components_process(#xmlel{name = <<"PREFIX">>, children = Value}, Acc) ->
222
:-(
maps:put(<<"prefix">>, process_value(Value), Acc);
223 name_components_process(#xmlel{name = <<"SUFFIX">>, children = Value}, Acc) ->
224
:-(
maps:put(<<"suffix">>, process_value(Value), Acc).
225
226 address_components_process(#xmlel{name = <<"POBOX">>, children = Value}, Acc) ->
227
:-(
maps:put(<<"pobox">>, process_value(Value), Acc);
228 address_components_process(#xmlel{name = <<"EXTADD">>, children = Value}, Acc) ->
229
:-(
maps:put(<<"extadd">>, process_value(Value), Acc);
230 address_components_process(#xmlel{name = <<"STREET">>, children = Value}, Acc) ->
231
:-(
maps:put(<<"street">>, process_value(Value), Acc);
232 address_components_process(#xmlel{name = <<"LOCALITY">>, children = Value}, Acc) ->
233
:-(
maps:put(<<"locality">>, process_value(Value), Acc);
234 address_components_process(#xmlel{name = <<"REGION">>, children = Value}, Acc) ->
235
:-(
maps:put(<<"region">>, process_value(Value), Acc);
236 address_components_process(#xmlel{name = <<"PCODE">>, children = Value}, Acc) ->
237
:-(
maps:put(<<"pcode">>, process_value(Value), Acc);
238 address_components_process(#xmlel{name = <<"CTRY">>, children = Value}, Acc) ->
239
:-(
maps:put(<<"country">>, process_value(Value), Acc);
240 address_components_process(#xmlel{name = Name, children = []}, Acc) ->
241
:-(
List = maps:get(<<"tags">>, Acc, []),
242
:-(
maps:merge(Acc, #{<<"tags">> => List ++ [{ok, Name}]}).
243
244 label_components_process(#xmlel{name = <<"LINE">>, children = Value}, Acc) ->
245
:-(
List = maps:get(<<"line">>, Acc, []),
246
:-(
maps:merge(Acc, #{<<"line">> => List ++ [{ok, process_value(Value)}]});
247 label_components_process(#xmlel{name = Name, children = []}, Acc) ->
248
:-(
List = maps:get(<<"tags">>, Acc, []),
249
:-(
maps:merge(Acc, #{<<"tags">> => List ++ [{ok, Name}]}).
250
251 telephone_components_process(#xmlel{name = <<"NUMBER">>, children = Value}, Acc) ->
252
:-(
maps:put(<<"number">>, process_value(Value), Acc);
253 telephone_components_process(#xmlel{name = Name, children = []}, Acc) ->
254
:-(
List = maps:get(<<"tags">>, Acc, []),
255
:-(
maps:merge(Acc, #{<<"tags">> => List ++ [{ok, Name}]}).
256
257 email_components_process(#xmlel{name = <<"USERID">>, children = Value}, Acc) ->
258
:-(
maps:put(<<"userId">>, process_value(Value), Acc);
259 email_components_process(#xmlel{name = Name, children = []}, Acc) ->
260
:-(
List = maps:get(<<"tags">>, Acc, []),
261
:-(
maps:merge(Acc, #{<<"tags">> => List ++ [{ok, Name}]}).
262
263 geo_components_process(#xmlel{name = <<"LAT">>, children = Value}, Acc) ->
264
:-(
maps:put(<<"lat">>, process_value(Value), Acc);
265 geo_components_process(#xmlel{name = <<"LON">>, children = Value}, Acc) ->
266
:-(
maps:put(<<"lon">>, process_value(Value), Acc).
267
268 org_components_process(#xmlel{name = <<"ORGNAME">>, children = Value}, Acc) ->
269
:-(
maps:put(<<"orgname">>, process_value(Value), Acc);
270 org_components_process(#xmlel{name = <<"ORGUNIT">>, children = Value}, Acc) ->
271
:-(
List = maps:get(<<"orgunit">>, Acc, []),
272
:-(
maps:merge(Acc, #{<<"orgunit">> => List ++ [{ok, process_value(Value)}]}).
273
274 categories_components_process(#xmlel{name = <<"KEYWORD">>, children = Value}, Acc) ->
275
:-(
List = maps:get(<<"keyword">>, Acc, []),
276
:-(
maps:merge(Acc, #{<<"keyword">> => List ++ [{ok, process_value(Value)}]}).
277
278 key_components_process(#xmlel{name = <<"CRED">>, children = Value}, Acc) ->
279
:-(
maps:put(<<"credential">>, process_value(Value), Acc);
280 key_components_process(#xmlel{name = <<"TYPE">>, children = Value}, Acc) ->
281
:-(
maps:put(<<"type">>, process_value(Value), Acc).
282
283 class_components_process(#xmlel{name = Name, children = []}, Acc) ->
284
:-(
List = maps:get(<<"tags">>, Acc, []),
285
:-(
maps:merge(Acc, #{<<"tags">> => List ++ [{ok, Name}]}).
286
287 image_components_process(#xmlel{name = <<"TYPE">>, children = Value}, Acc) ->
288
:-(
maps:put(<<"type">>, process_value(Value), Acc);
289 image_components_process(#xmlel{name = <<"BINVAL">>, children = Value}, Acc) ->
290
:-(
maps:put(<<"binValue">>, process_value(Value), Acc);
291 image_components_process(#xmlel{name = <<"EXTVAL">>, children = Value}, Acc) ->
292
:-(
maps:put(<<"extValue">>, process_value(Value), Acc).
293
294 sound_components_process(#xmlel{name = <<"PHONETIC">>, children = Value}, Acc) ->
295
:-(
maps:put(<<"phonetic">>, process_value(Value), Acc);
296 sound_components_process(#xmlel{name = <<"BINVAL">>, children = Value}, Acc) ->
297
:-(
maps:put(<<"binValue">>, process_value(Value), Acc);
298 sound_components_process(#xmlel{name = <<"EXTVAL">>, children = Value}, Acc) ->
299
:-(
maps:put(<<"extValue">>, process_value(Value), Acc).
300
301 agent_components_process(#xmlel{name = <<"vCard">>, children = Value}, Acc) ->
302
:-(
maps:put(<<"vcard">>, to_map_format(Value), Acc);
303 agent_components_process(#xmlel{name = <<"EXTVAL">>, children = Value}, Acc) ->
304
:-(
maps:put(<<"extValue">>, process_value(Value), Acc).
Line Hits Source