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