• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

processone / ejabberd / 603

17 Oct 2023 01:57PM UTC coverage: 32.654% (-0.4%) from 33.021%
603

push

github

badlop
Fixing minor typos in CHANGELOG

13497 of 41333 relevant lines covered (32.65%)

646.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

23.08
/src/mod_vcard_sql.erl
1
%%%-------------------------------------------------------------------
2
%%% File    : mod_vcard_sql.erl
3
%%% Author  : Evgeny Khramtsov <ekhramtsov@process-one.net>
4
%%% Created : 13 Apr 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
5
%%%
6
%%%
7
%%% ejabberd, Copyright (C) 2002-2023   ProcessOne
8
%%%
9
%%% This program is free software; you can redistribute it and/or
10
%%% modify it under the terms of the GNU General Public License as
11
%%% published by the Free Software Foundation; either version 2 of the
12
%%% License, or (at your option) any later version.
13
%%%
14
%%% This program is distributed in the hope that it will be useful,
15
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
16
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
%%% General Public License for more details.
18
%%%
19
%%% You should have received a copy of the GNU General Public License along
20
%%% with this program; if not, write to the Free Software Foundation, Inc.,
21
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
%%%
23
%%%----------------------------------------------------------------------
24

25
-module(mod_vcard_sql).
26

27

28
-behaviour(mod_vcard).
29

30
%% API
31
-export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4, remove_user/2,
32
         search_fields/1, search_reported/1, import/3, export/1]).
33
-export([is_search_supported/1]).
34

35
-include_lib("xmpp/include/xmpp.hrl").
36
-include("mod_vcard.hrl").
37
-include("logger.hrl").
38
-include("ejabberd_sql_pt.hrl").
39
-include("translate.hrl").
40

41
%%%===================================================================
42
%%% API
43
%%%===================================================================
44
init(Host, _Opts) ->
45
    ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
3✔
46
    ok.
3✔
47

48
schemas() ->
49
    [#sql_schema{
3✔
50
        version = 1,
51
        tables =
52
            [#sql_table{
53
                name = <<"vcard">>,
54
                columns =
55
                    [#sql_column{name = <<"username">>, type = text},
56
                     #sql_column{name = <<"server_host">>, type = text},
57
                     #sql_column{name = <<"vcard">>, type = {text, big}},
58
                     #sql_column{name = <<"created_at">>, type = timestamp,
59
                                 default = true}],
60
                indices = [#sql_index{
61
                              columns = [<<"server_host">>, <<"username">>],
62
                              unique = true}]},
63
             #sql_table{
64
                name = <<"vcard_search">>,
65
                columns =
66
                    [#sql_column{name = <<"username">>, type = text},
67
                     #sql_column{name = <<"lusername">>, type = text},
68
                     #sql_column{name = <<"server_host">>, type = text},
69
                     #sql_column{name = <<"fn">>, type = text},
70
                     #sql_column{name = <<"lfn">>, type = text},
71
                     #sql_column{name = <<"family">>, type = text},
72
                     #sql_column{name = <<"lfamily">>, type = text},
73
                     #sql_column{name = <<"given">>, type = text},
74
                     #sql_column{name = <<"lgiven">>, type = text},
75
                     #sql_column{name = <<"middle">>, type = text},
76
                     #sql_column{name = <<"lmiddle">>, type = text},
77
                     #sql_column{name = <<"nickname">>, type = text},
78
                     #sql_column{name = <<"lnickname">>, type = text},
79
                     #sql_column{name = <<"bday">>, type = text},
80
                     #sql_column{name = <<"lbday">>, type = text},
81
                     #sql_column{name = <<"ctry">>, type = text},
82
                     #sql_column{name = <<"lctry">>, type = text},
83
                     #sql_column{name = <<"locality">>, type = text},
84
                     #sql_column{name = <<"llocality">>, type = text},
85
                     #sql_column{name = <<"email">>, type = text},
86
                     #sql_column{name = <<"lemail">>, type = text},
87
                     #sql_column{name = <<"orgname">>, type = text},
88
                     #sql_column{name = <<"lorgname">>, type = text},
89
                     #sql_column{name = <<"orgunit">>, type = text},
90
                     #sql_column{name = <<"lorgunit">>, type = text}],
91
                indices = [#sql_index{
92
                              columns = [<<"server_host">>, <<"lusername">>],
93
                              unique = true},
94
                           #sql_index{
95
                              columns = [<<"server_host">>, <<"lfn">>]},
96
                           #sql_index{
97
                              columns = [<<"server_host">>, <<"lfamily">>]},
98
                           #sql_index{
99
                              columns = [<<"server_host">>, <<"lgiven">>]},
100
                           #sql_index{
101
                              columns = [<<"server_host">>, <<"lmiddle">>]},
102
                           #sql_index{
103
                              columns = [<<"server_host">>, <<"lnickname">>]},
104
                           #sql_index{
105
                              columns = [<<"server_host">>, <<"lbday">>]},
106
                           #sql_index{
107
                              columns = [<<"server_host">>, <<"lctry">>]},
108
                           #sql_index{
109
                              columns = [<<"server_host">>, <<"llocality">>]},
110
                           #sql_index{
111
                              columns = [<<"server_host">>, <<"lemail">>]},
112
                           #sql_index{
113
                              columns = [<<"server_host">>, <<"lorgname">>]},
114
                           #sql_index{
115
                              columns = [<<"server_host">>, <<"lorgunit">>]}]}]}].
116

117
stop(_Host) ->
118
    ok.
3✔
119

120
is_search_supported(_LServer) ->
121
    true.
×
122

123
get_vcard(LUser, LServer) ->
124
    case ejabberd_sql:sql_query(
12✔
125
           LServer,
126
           ?SQL("select @(vcard)s from vcard"
12✔
127
                " where username=%(LUser)s and %(LServer)H")) of
128
        {selected, [{SVCARD}]} ->
129
            case fxml_stream:parse_element(SVCARD) of
3✔
130
                {error, _Reason} -> error;
×
131
                VCARD -> {ok, [VCARD]}
3✔
132
            end;
133
        {selected, []} -> {ok, []};
9✔
134
        _ -> error
×
135
    end.
136

137
set_vcard(LUser, LServer, VCARD,
138
          #vcard_search{user = {User, _},
139
                        fn = FN,
140
                        lfn = LFN,
141
                        family = Family,
142
                        lfamily = LFamily,
143
                        given = Given,
144
                        lgiven = LGiven,
145
                        middle = Middle,
146
                        lmiddle = LMiddle,
147
                        nickname = Nickname,
148
                        lnickname = LNickname,
149
                        bday = BDay,
150
                        lbday = LBDay,
151
                        ctry = CTRY,
152
                        lctry = LCTRY,
153
                        locality = Locality,
154
                        llocality = LLocality,
155
                        email = EMail,
156
                        lemail = LEMail,
157
                        orgname = OrgName,
158
                        lorgname = LOrgName,
159
                        orgunit = OrgUnit,
160
                        lorgunit = LOrgUnit}) ->
161
    SVCARD = fxml:element_to_binary(VCARD),
3✔
162
    ejabberd_sql:sql_transaction(
3✔
163
      LServer,
164
      fun() ->
165
              ?SQL_UPSERT(LServer, "vcard",
3✔
166
                          ["!username=%(LUser)s",
167
                           "!server_host=%(LServer)s",
168
                           "vcard=%(SVCARD)s"]),
169
              ?SQL_UPSERT(LServer, "vcard_search",
3✔
170
                          ["username=%(User)s",
171
                           "!lusername=%(LUser)s",
172
                           "!server_host=%(LServer)s",
173
                           "fn=%(FN)s",
174
                           "lfn=%(LFN)s",
175
                           "family=%(Family)s",
176
                           "lfamily=%(LFamily)s",
177
                           "given=%(Given)s",
178
                           "lgiven=%(LGiven)s",
179
                           "middle=%(Middle)s",
180
                           "lmiddle=%(LMiddle)s",
181
                           "nickname=%(Nickname)s",
182
                           "lnickname=%(LNickname)s",
183
                           "bday=%(BDay)s",
184
                           "lbday=%(LBDay)s",
185
                           "ctry=%(CTRY)s",
186
                           "lctry=%(LCTRY)s",
187
                           "locality=%(Locality)s",
188
                           "llocality=%(LLocality)s",
189
                           "email=%(EMail)s",
190
                           "lemail=%(LEMail)s",
191
                           "orgname=%(OrgName)s",
192
                           "lorgname=%(LOrgName)s",
193
                           "orgunit=%(OrgUnit)s",
194
                           "lorgunit=%(LOrgUnit)s"])
195
      end).
196

197
search(LServer, Data, AllowReturnAll, MaxMatch) ->
198
    MatchSpec = make_matchspec(LServer, Data),
×
199
    if (MatchSpec == <<"">>) and not AllowReturnAll -> [];
×
200
       true ->
201
            Limit = case MaxMatch of
×
202
                        infinity ->
203
                            <<"">>;
×
204
                        Val ->
205
                            [<<" LIMIT ">>, integer_to_binary(Val)]
×
206
                    end,
207
           case catch ejabberd_sql:sql_query(
×
208
                        LServer,
209
                        [<<"select username, fn, family, given, "
210
                           "middle,        nickname, bday, ctry, "
211
                           "locality,        email, orgname, orgunit "
212
                           "from vcard_search ">>,
213
                         MatchSpec, Limit, <<";">>]) of
214
               {selected,
215
                [<<"username">>, <<"fn">>, <<"family">>, <<"given">>,
216
                 <<"middle">>, <<"nickname">>, <<"bday">>, <<"ctry">>,
217
                 <<"locality">>, <<"email">>, <<"orgname">>,
218
                 <<"orgunit">>], Rs} when is_list(Rs) ->
219
                   [row_to_item(LServer, R) || R <- Rs];
×
220
               Error ->
221
                   ?ERROR_MSG("~p", [Error]), []
×
222
           end
223
    end.
224

225
search_fields(_LServer) ->
226
    [{?T("User"), <<"user">>},
×
227
     {?T("Full Name"), <<"fn">>},
228
     {?T("Name"), <<"first">>},
229
     {?T("Middle Name"), <<"middle">>},
230
     {?T("Family Name"), <<"last">>},
231
     {?T("Nickname"), <<"nick">>},
232
     {?T("Birthday"), <<"bday">>},
233
     {?T("Country"), <<"ctry">>},
234
     {?T("City"), <<"locality">>},
235
     {?T("Email"), <<"email">>},
236
     {?T("Organization Name"), <<"orgname">>},
237
     {?T("Organization Unit"), <<"orgunit">>}].
238

239
search_reported(_LServer) ->
240
    [{?T("Jabber ID"), <<"jid">>},
×
241
     {?T("Full Name"), <<"fn">>},
242
     {?T("Name"), <<"first">>},
243
     {?T("Middle Name"), <<"middle">>},
244
     {?T("Family Name"), <<"last">>},
245
     {?T("Nickname"), <<"nick">>},
246
     {?T("Birthday"), <<"bday">>},
247
     {?T("Country"), <<"ctry">>},
248
     {?T("City"), <<"locality">>},
249
     {?T("Email"), <<"email">>},
250
     {?T("Organization Name"), <<"orgname">>},
251
     {?T("Organization Unit"), <<"orgunit">>}].
252

253
remove_user(LUser, LServer) ->
254
    ejabberd_sql:sql_transaction(
6✔
255
      LServer,
256
      fun() ->
257
              ejabberd_sql:sql_query_t(
6✔
258
                ?SQL("delete from vcard"
6✔
259
                     " where username=%(LUser)s and %(LServer)H")),
260
              ejabberd_sql:sql_query_t(
6✔
261
                ?SQL("delete from vcard_search"
6✔
262
                     " where lusername=%(LUser)s and %(LServer)H"))
263
      end).
264

265
export(_Server) ->   
266
    [{vcard,
×
267
      fun(Host, #vcard{us = {LUser, LServer}, vcard = VCARD})
268
            when LServer == Host ->
269
              SVCARD = fxml:element_to_binary(VCARD),
×
270
              [?SQL("delete from vcard"
×
271
                    " where username=%(LUser)s and %(LServer)H;"),
272
               ?SQL_INSERT("vcard",
×
273
                           ["username=%(LUser)s",
274
                            "server_host=%(LServer)s",
275
                            "vcard=%(SVCARD)s"])];
276
         (_Host, _R) ->
277
              []
×
278
      end},
279
     {vcard_search,
280
      fun(Host, #vcard_search{user = {User, LServer}, luser = LUser,
281
                              fn = FN, lfn = LFN, family = Family,
282
                              lfamily = LFamily, given = Given,
283
                              lgiven = LGiven, middle = Middle,
284
                              lmiddle = LMiddle, nickname = Nickname,
285
                              lnickname = LNickname, bday = BDay,
286
                              lbday = LBDay, ctry = CTRY, lctry = LCTRY,
287
                              locality = Locality, llocality = LLocality,
288
                              email = EMail, lemail = LEMail,
289
                              orgname = OrgName, lorgname = LOrgName,
290
                              orgunit = OrgUnit, lorgunit = LOrgUnit})
291
            when LServer == Host ->
292
              [?SQL("delete from vcard_search"
×
293
                    " where lusername=%(LUser)s and %(LServer)H;"),
294
               ?SQL_INSERT("vcard_search",
×
295
                           ["username=%(User)s",
296
                            "lusername=%(LUser)s",
297
                            "server_host=%(LServer)s",
298
                            "fn=%(FN)s",
299
                            "lfn=%(LFN)s",
300
                            "family=%(Family)s",
301
                            "lfamily=%(LFamily)s",
302
                            "given=%(Given)s",
303
                            "lgiven=%(LGiven)s",
304
                            "middle=%(Middle)s",
305
                            "lmiddle=%(LMiddle)s",
306
                            "nickname=%(Nickname)s",
307
                            "lnickname=%(LNickname)s",
308
                            "bday=%(BDay)s",
309
                            "lbday=%(LBDay)s",
310
                            "ctry=%(CTRY)s",
311
                            "lctry=%(LCTRY)s",
312
                            "locality=%(Locality)s",
313
                            "llocality=%(LLocality)s",
314
                            "email=%(EMail)s",
315
                            "lemail=%(LEMail)s",
316
                            "orgname=%(OrgName)s",
317
                            "lorgname=%(LOrgName)s",
318
                            "orgunit=%(OrgUnit)s",
319
                            "lorgunit=%(LOrgUnit)s"])];
320
         (_Host, _R) ->
321
              []
×
322
      end}].
323

324
import(_, _, _) ->
325
    ok.
×
326

327
%%%===================================================================
328
%%% Internal functions
329
%%%===================================================================
330
make_matchspec(LServer, Data) ->
331
    filter_fields(Data, <<"">>, LServer).
×
332

333
filter_fields([], Match, LServer) ->
334
    case ejabberd_sql:use_new_schema() of
×
335
        true ->
336
            SQLType = ejabberd_option:sql_type(LServer),
×
337
            SServer = ejabberd_sql:to_string_literal(SQLType, LServer),
×
338
            case Match of
×
339
                <<"">> -> [<<"where server_host=">>, SServer];
×
340
                _ -> [<<" where server_host=">>, SServer, <<" and ">>, Match]
×
341
            end;
342
        false ->
343
            case Match of
×
344
                <<"">> -> <<"">>;
×
345
                _ -> [<<" where ">>, Match]
×
346
            end
347
    end;
348
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
349
  when is_binary(Val) and (Val /= <<"">>) ->
350
    LVal = mod_vcard:string2lower(Val),
×
351
    NewMatch = case SVar of
×
352
                   <<"user">> -> make_val(LServer, Match, <<"lusername">>, LVal);
×
353
                   <<"fn">> -> make_val(LServer, Match, <<"lfn">>, LVal);
×
354
                   <<"last">> -> make_val(LServer, Match, <<"lfamily">>, LVal);
×
355
                   <<"first">> -> make_val(LServer, Match, <<"lgiven">>, LVal);
×
356
                   <<"middle">> -> make_val(LServer, Match, <<"lmiddle">>, LVal);
×
357
                   <<"nick">> -> make_val(LServer, Match, <<"lnickname">>, LVal);
×
358
                   <<"bday">> -> make_val(LServer, Match, <<"lbday">>, LVal);
×
359
                   <<"ctry">> -> make_val(LServer, Match, <<"lctry">>, LVal);
×
360
                   <<"locality">> ->
361
                       make_val(LServer, Match, <<"llocality">>, LVal);
×
362
                   <<"email">> -> make_val(LServer, Match, <<"lemail">>, LVal);
×
363
                   <<"orgname">> -> make_val(LServer, Match, <<"lorgname">>, LVal);
×
364
                   <<"orgunit">> -> make_val(LServer, Match, <<"lorgunit">>, LVal);
×
365
                   _ -> Match
×
366
               end,
367
    filter_fields(Ds, NewMatch, LServer);
×
368
filter_fields([_ | Ds], Match, LServer) ->
369
    filter_fields(Ds, Match, LServer).
×
370

371
make_val(LServer, Match, Field, Val) ->
372
    Condition = case str:suffix(<<"*">>, Val) of
×
373
                  true ->
374
                      Val1 = str:substr(Val, 1, byte_size(Val) - 1),
×
375
                      SVal = <<(ejabberd_sql:escape(
×
376
                                  ejabberd_sql:escape_like_arg_circumflex(
377
                                    Val1)))/binary,
378
                               "%">>,
379
                      [Field, <<" LIKE '">>, SVal, <<"' ESCAPE '^'">>];
×
380
                  _ ->
381
                      SQLType = ejabberd_option:sql_type(LServer),
×
382
                      SVal = ejabberd_sql:to_string_literal(SQLType, Val),
×
383
                      [Field, <<" = ">>, SVal]
×
384
                end,
385
    case Match of
×
386
      <<"">> -> Condition;
×
387
      _ -> [Match, <<" and ">>, Condition]
×
388
    end.
389

390
row_to_item(LServer, [Username, FN, Family, Given, Middle, Nickname, BDay,
391
                      CTRY, Locality, EMail, OrgName, OrgUnit]) ->
392
    [{<<"jid">>, <<Username/binary, $@, LServer/binary>>},
×
393
     {<<"fn">>, FN},
394
     {<<"last">>, Family},
395
     {<<"first">>, Given},
396
     {<<"middle">>, Middle},
397
     {<<"nick">>, Nickname},
398
     {<<"bday">>, BDay},
399
     {<<"ctry">>, CTRY},
400
     {<<"locality">>, Locality},
401
     {<<"email">>, EMail},
402
     {<<"orgname">>, OrgName},
403
     {<<"orgunit">>, OrgUnit}].
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc