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

GrottoCenter / grottocenter-api / 19573421495

21 Nov 2025 09:43AM UTC coverage: 45.853% (-0.5%) from 46.323%
19573421495

Pull #1407

github

vmarseguerra
feat(search): uses Typesense as a search database
Pull Request #1407: Search improvements

1040 of 2997 branches covered (34.7%)

Branch coverage included in aggregate %.

123 of 477 new or added lines in 48 files covered. (25.79%)

52 existing lines in 10 files now uncovered.

3084 of 5997 relevant lines covered (51.43%)

6.91 hits per line

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

86.0
/api/services/CaverService.js
1
const CommonService = require('./CommonService');
6✔
2
const SearchService = require('./SearchService');
6✔
3
const NameService = require('./NameService');
6✔
4

5
module.exports = {
6✔
6
  isARealCaver: async (email) =>
7
    email && !email.toLowerCase().endsWith('@mail.no'),
77✔
8

9
  /**
10
   * Count the "real" users (@see REAL_USERS_QUERY)
11
   */
12
  countDistinctUsers: async () => {
13
    // Non-users caver like authors (and with the email ending with @mail.no) have no password set.
14
    const REAL_USERS_QUERY = 'SELECT count(password) FROM t_caver';
1✔
15
    const result = await CommonService.query(REAL_USERS_QUERY);
1✔
16
    return Number(result.rows[0].count);
1✔
17
  },
18

19
  /**
20
   * @param {Object} caverData
21
   * @param {string} caverData.nickname
22
   * @param {string} [caverData.name]
23
   * @param {string} [caverData.surname]
24
   * @throws Sails ORM errors (see https://sailsjs.com/documentation/concepts/models-and-orm/errors)
25
   * @returns {TCaver} the created caver
26
   */
27
  createNonUserCaver: async (caverData) => {
28
    let nickname = caverData?.nickname ?? '';
2✔
29
    const name = caverData?.name ?? undefined;
2!
30
    const surname = caverData?.surname ?? undefined;
2!
31
    if (nickname === '') {
2✔
32
      if (name) {
1!
33
        nickname += name;
1✔
34
      }
35
      if (surname) {
1!
36
        const space = name ? ' ' : '';
1!
37
        nickname += space + surname;
1✔
38
      }
39
    }
40

41
    const newCaver = await TCaver.create({
2✔
42
      dateInscription: new Date(),
43
      mail: `${+new Date()}@mail.no`, // default mail for non-user caver
44
      mailIsValid: false,
45
      name,
46
      nickname,
47
      surname,
48
      language: '000', // default null language id
49
    }).fetch();
50

51
    await module.exports.updateInSearch(newCaver);
2✔
52

53
    return newCaver;
2✔
54
  },
55

56
  /**
57
   * @param {Integer} caverId
58
   * @throws Sails ORM errors (see https://sailsjs.com/documentation/concepts/models-and-orm/errors)
59
   * @description Get a caver by his id and populate it according to the user rights (using req).
60
   * @returns {Object}
61
   */
62
  getCaver: async (caverId) => {
63
    const caver = await TCaver.findOne(caverId)
6✔
64
      .populate('documents', {
65
        limit: 10,
66
        sort: [{ dateInscription: 'DESC' }],
67
      })
68
      .populate('exploredEntrances', {
69
        limit: 10,
70
        sort: [{ dateInscription: 'DESC' }],
71
      })
72
      .populate('grottos')
73
      .populate('groups')
74
      .populate('subscribedToCountries')
75
      .populate('subscribedToMassifs');
76

77
    if (!caver) return null;
6✔
78

79
    // Delete sensitive data
80
    delete caver.activationCode;
4✔
81
    delete caver.password;
4✔
82

83
    caver.type = module.exports.isARealCaver(caver.mail) ? 'CAVER' : 'AUTHOR';
4!
84

85
    const asyncArr = [
4✔
86
      NameService.setNames(caver.exploredEntrances, 'entrance'),
87
      NameService.setNames(caver.grottos, 'grotto'),
88
      NameService.setNames(caver.subscribedToMassifs, 'massif'),
89
    ];
90

91
    await Promise.all(asyncArr);
4✔
92

93
    return {
4✔
94
      id: caver.id,
95
      type: caver.type,
96
      name: caver.name,
97
      surname: caver.surname,
98
      nickname: caver.nickname,
99
      language: caver.language,
100
      groups: caver.groups,
101
      grottos: caver.grottos,
102
      exploredEntrances: caver.exploredEntrances,
103
      documents: caver.documents,
104
      subscribedToMassifs: caver.subscribedToMassifs,
105
      subscribedToCountries: caver.subscribedToCountries,
106
    };
107
  },
108

109
  async deleteInSearch(caverId) {
NEW
110
    await SearchService.deleteDocument('persons', caverId);
×
111
  },
112

113
  async updateInSearch(caver) {
114
    await SearchService.updateDocument('persons', {
6✔
115
      id: caver.id,
116
      dateInscription: caver.dateInscription,
117
      mail: caver.mail,
118
      name: caver.name,
119
      surname: caver.surname,
120
      nickname: caver.nickname,
121
    });
122
  },
123
};
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