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

GrottoCenter / grottocenter-api / 19535172246

20 Nov 2025 10:59AM UTC coverage: 45.853% (-0.5%) from 46.316%
19535172246

push

github

vmarseguerra
feat(search): uses Typesense as a search database

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%)

9 existing lines in 9 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

7.46
/api/controllers/v1/document/multiple-validate.js
1
const DocumentService = require('../../../services/DocumentService');
1✔
2
const FileService = require('../../../services/FileService');
1✔
3
const RightService = require('../../../services/RightService');
1✔
4
const NotificationService = require('../../../services/NotificationService');
1✔
5

6
async function markDocumentValidated(
7
  documentId,
8
  validationComment,
9
  validationAuthor
10
) {
11
  await TDocument.updateOne(documentId).set({
×
12
    isValidated: true,
13
    modifiedDocJson: null,
14
    dateValidation: new Date(),
15
    validationComment,
16
    validator: validationAuthor,
17
  });
18
}
19

20
async function validateAndUpdateDocument(
21
  document,
22
  validationComment,
23
  validationAuthor
24
) {
25
  const {
26
    reviewerId,
27
    documentData,
28
    descriptionData,
29
    modifiedFiles,
30
    deletedFiles,
31
    newFiles,
32
  } = document.modifiedDocJson;
×
33

34
  await sails.getDatastore().transaction(async (db) => {
×
35
    // Update associated data not handled by TDocument manually
36
    // Updated before the TDocument update so the last_change_document DB trigger will fetch the last updated name
37
    await TDescription.updateOne({ document: document.id })
×
38
      .set(descriptionData)
39
      .usingConnection(db);
40

41
    await TDocument.updateOne(document.id)
×
42
      .set({
43
        ...documentData,
44
        modifiedDocJson: null,
45
        dateReviewed: new Date(),
46
        reviewer: reviewerId,
47
        dateValidation: new Date(),
48
        isValidated: true,
49
        validationComment,
50
        validator: validationAuthor,
51
      })
52
      .usingConnection(db);
53

54
    const filePromises = [];
×
55
    // Files have already been created,
56
    // they just need to be linked to the document.
57
    if (newFiles) {
×
58
      filePromises.push(
×
59
        ...newFiles.map((f) => TFile.updateOne(f.id).set({ isValidated: true }))
×
60
      );
61
    }
62
    if (modifiedFiles) {
×
63
      filePromises.push(
×
64
        ...modifiedFiles.map((f) => FileService.document.update(f))
×
65
      );
66
    }
67

68
    if (deletedFiles) {
×
69
      filePromises.push(
×
70
        ...deletedFiles.map((f) => FileService.document.delete(f))
×
71
      );
72
    }
73
    await Promise.all(filePromises);
×
74
  });
75
}
76

77
async function updateSearchAndNotify(req, documentId, userId) {
78
  const document = await DocumentService.getPopulatedDocument(documentId);
×
NEW
79
  await DocumentService.updateInSearch(document);
×
80

81
  await NotificationService.notifySubscribers(
×
82
    req,
83
    document,
84
    userId,
85
    NotificationService.NOTIFICATION_TYPES.VALIDATE,
86
    NotificationService.NOTIFICATION_ENTITIES.DOCUMENT
87
  );
88
}
89

90
module.exports = async (req, res) => {
1✔
91
  const hasRight = RightService.hasGroup(
×
92
    req.token.groups,
93
    RightService.G.MODERATOR
94
  );
95
  if (!hasRight) {
×
96
    return res.forbidden(
×
97
      'You are not authorized to validate multiple documents.'
98
    );
99
  }
100

101
  const documentChanges = [];
×
102
  // Validate input
103
  for (const doc of req.param('documents') ?? []) {
×
104
    // Whether or not the pending changes are accepted or not
105
    const isValidated = doc.isValidated
×
106
      ? doc.isValidated.toLowerCase() !== 'false'
107
      : true;
108

109
    if (isValidated === false && !doc.validationComment) {
×
110
      return res.badRequest(
×
111
        `If the document with id ${doc.id} is refused, a comment must be provided.`
112
      );
113
    }
114

115
    documentChanges.push({
×
116
      id: doc.id,
117
      isValidated,
118
      validationComment: doc.validationComment,
119
    });
120
  }
121
  const documentIds = documentChanges.map((e) => e.id);
×
122
  const foundDocuments = await TDocument.find({ id: documentIds });
×
123

124
  for (const document of foundDocuments) {
×
125
    const change = documentChanges.find((d) => d.id === document.id);
×
126
    const isAModifiedDoc = !!document.modifiedDocJson;
×
127
    if (!change.isValidated) {
×
128
      // Validate it but do not update its fields (reject change)
129
      // eslint-disable-next-line no-await-in-loop
130
      await markDocumentValidated(
×
131
        document.id,
132
        change.validationComment,
133
        req.token.id
134
      );
135
      continue; // eslint-disable-line no-continue
×
136
    }
137

138
    if (isAModifiedDoc) {
×
139
      // eslint-disable-next-line no-await-in-loop
140
      await validateAndUpdateDocument(
×
141
        document,
142
        change.validationComment,
143
        req.token.id
144
      );
145
    } else {
146
      // Likely a document creation
147
      // eslint-disable-next-line no-await-in-loop
148
      await markDocumentValidated(
×
149
        document.id,
150
        change.validationComment,
151
        req.token.id
152
      );
153
    }
154

155
    // eslint-disable-next-line no-await-in-loop
NEW
156
    await updateSearchAndNotify(res, document.id, req.token.id).catch((err) =>
×
UNCOV
157
      sails.log.error(
×
158
        'Document multiple validate updateSearchAndNotify error',
159
        document,
160
        err
161
      )
162
    );
163
  }
164

165
  return res.ok();
×
166
};
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