./ct_report/coverage/mod_vcard_mnesia.COVER.html

1 -module(mod_vcard_mnesia).
2
3 -behaviour(mod_vcard_backend).
4
5 %% mod_vcards callbacks
6 -export([init/2,
7 remove_user/3,
8 get_vcard/3,
9 set_vcard/5,
10 search/3,
11 search_fields/2,
12 search_reported_fields/3]).
13
14 -include("mongoose.hrl").
15 -include("jlib.hrl").
16 -include("mod_vcard.hrl").
17
18 init(_HostType, _Options) ->
19 413 prepare_db(),
20 413 ok.
21
22 remove_user(_HostType, LUser, LServer) ->
23 3031 US = {LUser, LServer},
24 3031 F = fun() ->
25 3031 mnesia:delete({vcard, US}),
26 3031 mnesia:delete({vcard_search, US})
27 end,
28 3031 mnesia:transaction(F).
29
30 get_vcard(_HostType, LUser, LServer) ->
31 83 US = {LUser, LServer},
32 83 F = fun() ->
33 83 mnesia:read({vcard, US})
34 end,
35 83 case mnesia:transaction(F) of
36 {atomic, []} ->
37 54 {error, mongoose_xmpp_errors:item_not_found()};
38 {atomic, Rs} ->
39 29 Els = lists:map(fun(R) ->
40 29 R#vcard.vcard
41 end, Rs),
42 29 {ok, Els};
43 {aborted, Reason} ->
44
:-(
?LOG_ERROR(#{what => process_sm_iq_vcard_lookup_failed,
45
:-(
reason => Reason, user => LUser, server => LServer}),
46
:-(
{error, mongoose_xmpp_errors:internal_server_error()}
47 end.
48
49 set_vcard(HostType, User, LServer, VCard, VCardSearch) ->
50 30 LUser = jid:nodeprep(User),
51 30 VCardSearch2 = stringify_search_fields(VCardSearch),
52 30 F = fun() ->
53 30 mnesia:write(#vcard{us ={LUser, LServer}, vcard = VCard}),
54 30 mnesia:write(VCardSearch2)
55 end,
56 30 {atomic, _} = mnesia:transaction(F),
57 30 mongoose_hooks:vcard_set(HostType, LServer, LUser, VCard),
58 30 ok.
59
60 -spec search(mongooseim:host_type(), jid:lserver(), term()) -> [[mongoose_data_forms:field()]].
61 search(HostType, LServer, Data) ->
62 19 MatchHead = make_matchhead(LServer, Data),
63 19 R = do_search(HostType, LServer, MatchHead),
64 19 lists:map(fun record_to_item/1, R).
65
66 do_search(_, _, #vcard_search{_ = '_'}) ->
67 2 [];
68 do_search(HostType, LServer, MatchHeadIn) ->
69 17 MatchHead = MatchHeadIn#vcard_search{us = {'_', LServer}},
70 17 case catch mnesia:dirty_select(vcard_search,
71 [{MatchHead, [], ['$_']}]) of
72 {'EXIT', Reason} ->
73
:-(
?LOG_ERROR(#{what => vcard_search_failed, server => LServer, host_type => HostType,
74
:-(
reason => Reason}),
75
:-(
[];
76 Rs ->
77 17 case mod_vcard:get_results_limit(HostType) of
78 infinity ->
79
:-(
Rs;
80 Val ->
81 17 lists:sublist(Rs, Val)
82 end
83 end.
84
85 search_fields(_HostType, _LServer) ->
86 2 mod_vcard:default_search_fields().
87
88 -spec search_reported_fields(mongooseim:host_type(), jid:lserver(), ejabberd:lang()) ->
89 [mongoose_data_forms:field()].
90 search_reported_fields(_HostType, _LServer, Lang) ->
91 19 mod_vcard:get_default_reported_fields(Lang).
92
93 %%--------------------------------------------------------------------
94 %% internal
95 %%--------------------------------------------------------------------
96
97 prepare_db() ->
98 413 create_tables(),
99 413 set_indexes(),
100 413 add_table_copies().
101
102 create_tables() ->
103 413 mongoose_mnesia:create_table(vcard,
104 [{disc_only_copies, [node()]},
105 {attributes, record_info(fields, vcard)}]),
106 413 mongoose_mnesia:create_table(vcard_search,
107 [{disc_copies, [node()]},
108 {attributes, record_info(fields, vcard_search)}]).
109
110 add_table_copies() ->
111 413 mnesia:add_table_copy(vcard, node(), disc_only_copies),
112 413 mnesia:add_table_copy(vcard_search, node(), disc_copies).
113
114 set_indexes() ->
115 413 mnesia:add_table_index(vcard_search, luser),
116 413 mnesia:add_table_index(vcard_search, lfn),
117 413 mnesia:add_table_index(vcard_search, lfamily),
118 413 mnesia:add_table_index(vcard_search, lgiven),
119 413 mnesia:add_table_index(vcard_search, lmiddle),
120 413 mnesia:add_table_index(vcard_search, lnickname),
121 413 mnesia:add_table_index(vcard_search, lbday),
122 413 mnesia:add_table_index(vcard_search, lctry),
123 413 mnesia:add_table_index(vcard_search, llocality),
124 413 mnesia:add_table_index(vcard_search, lemail),
125 413 mnesia:add_table_index(vcard_search, lorgname),
126 413 mnesia:add_table_index(vcard_search, lorgunit).
127
128 make_matchhead(LServer, Data) ->
129 19 GlobMatch = #vcard_search{_ = '_'},
130 19 Match = filter_fields(Data, GlobMatch, LServer),
131 19 Match.
132
133 filter_fields([], Match, _LServer) ->
134 19 Match;
135 filter_fields([{SVar, [Val]} | Ds], Match, LServer)
136 when is_binary(Val) and (Val /= <<"">>) ->
137 18 LVal = jid:str_tolower(Val),
138 18 NewMatch =
139 case SVar of
140
:-(
<<"user">> -> Match#vcard_search{luser = make_val(LVal)};
141 14 <<"fn">> -> Match#vcard_search{lfn = make_val(LVal)};
142 2 <<"last">> -> Match#vcard_search{lfamily = make_val(LVal)};
143 1 <<"first">> -> Match#vcard_search{lgiven = make_val(LVal)};
144
:-(
<<"middle">> -> Match#vcard_search{lmiddle = make_val(LVal)};
145
:-(
<<"nick">> -> Match#vcard_search{lnickname = make_val(LVal)};
146
:-(
<<"bday">> -> Match#vcard_search{lbday = make_val(LVal)};
147
:-(
<<"ctry">> -> Match#vcard_search{lctry = make_val(LVal)};
148 1 <<"locality">> -> Match#vcard_search{llocality = make_val(LVal)};
149
:-(
<<"email">> -> Match#vcard_search{lemail = make_val(LVal)};
150
:-(
<<"orgname">> -> Match#vcard_search{lorgname = make_val(LVal)};
151
:-(
<<"orgunit">> -> Match#vcard_search{lorgunit = make_val(LVal)};
152
:-(
_ -> Match
153 end,
154 18 filter_fields(Ds, NewMatch, LServer);
155 filter_fields([_ | Ds], Match, LServer) ->
156
:-(
filter_fields(Ds, Match, LServer).
157
158 %% Fulltext search is mnesia is something that is really-really wrong
159 stringify_search_fields(#vcard_search{} = S) ->
160 30 S#vcard_search{
161 lfn = binary_to_list(S#vcard_search.lfn),
162 lfamily = binary_to_list(S#vcard_search.lfamily),
163 luser = binary_to_list(S#vcard_search.luser),
164 lgiven = binary_to_list(S#vcard_search.lgiven),
165 lmiddle = binary_to_list(S#vcard_search.lmiddle),
166 lnickname = binary_to_list(S#vcard_search.lnickname),
167 lbday = binary_to_list(S#vcard_search.lbday),
168 lctry = binary_to_list(S#vcard_search.lctry),
169 llocality = binary_to_list(S#vcard_search.llocality),
170 lemail = binary_to_list(S#vcard_search.lemail),
171 lorgname = binary_to_list(S#vcard_search.lorgname),
172 lorgunit = binary_to_list(S#vcard_search.lorgunit)
173 }.
174
175 %% returns value as list to match substrings using match spec.
176 %% See vcard_search definition.
177 make_val(ValBin) ->
178 18 Val = binary_to_list(ValBin),
179 18 case lists:suffix("*", Val) of
180 true ->
181 11 lists:sublist(Val, length(Val) - 1) ++ '_';
182 _ ->
183 7 Val
184 end.
185
186 record_to_item(R) ->
187 25 {User, Server} = R#vcard_search.user,
188 25 [
189 ?FIELD(<<"jid">>, <<User/binary, $@, Server/binary>>),
190 ?FIELD(<<"fn">>, (R#vcard_search.fn)),
191 ?FIELD(<<"last">>, (R#vcard_search.family)),
192 ?FIELD(<<"first">>, (R#vcard_search.given)),
193 ?FIELD(<<"middle">>, (R#vcard_search.middle)),
194 ?FIELD(<<"nick">>, (R#vcard_search.nickname)),
195 ?FIELD(<<"bday">>, (R#vcard_search.bday)),
196 ?FIELD(<<"ctry">>, (R#vcard_search.ctry)),
197 ?FIELD(<<"locality">>, (R#vcard_search.locality)),
198 ?FIELD(<<"email">>, (R#vcard_search.email)),
199 ?FIELD(<<"orgname">>, (R#vcard_search.orgname)),
200 ?FIELD(<<"orgunit">>, (R#vcard_search.orgunit))
201 ].
Line Hits Source