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

GrottoCenter / grottocenter-api / 19671332439

25 Nov 2025 01:33PM UTC coverage: 85.128% (+38.8%) from 46.323%
19671332439

push

github

vmarseguerra
chore(logging): add trace-id capability. Logs requests when a 5xx is returned

2441 of 3029 branches covered (80.59%)

Branch coverage included in aggregate %.

34 of 39 new or added lines in 4 files covered. (87.18%)

72 existing lines in 17 files now uncovered.

5281 of 6042 relevant lines covered (87.4%)

21.56 hits per line

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

82.09
/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({
4✔
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;
1✔
33

34
  await sails.getDatastore().transaction(async (db) => {
1✔
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 })
1✔
38
      .set(descriptionData)
39
      .usingConnection(db);
40

41
    await TDocument.updateOne(document.id)
1✔
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 = [];
1✔
55
    // Files have already been created,
56
    // they just need to be linked to the document.
57
    if (newFiles) {
1!
58
      filePromises.push(
×
59
        ...newFiles.map((f) => TFile.updateOne(f.id).set({ isValidated: true }))
×
60
      );
61
    }
62
    if (modifiedFiles) {
1!
63
      filePromises.push(
×
64
        ...modifiedFiles.map((f) => FileService.document.update(f))
×
65
      );
66
    }
67

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

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

81
  await NotificationService.notifySubscribers(
4✔
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(
7✔
92
    req.token.groups,
93
    RightService.G.MODERATOR
94
  );
95
  if (!hasRight) {
7✔
96
    return res.forbidden(
1✔
97
      'You are not authorized to validate multiple documents.'
98
    );
99
  }
100

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

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

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

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

138
    if (isAModifiedDoc) {
4✔
139
      // eslint-disable-next-line no-await-in-loop
140
      await validateAndUpdateDocument(
1✔
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(
3✔
149
        document.id,
150
        change.validationComment,
151
        req.token.id
152
      );
153
    }
154

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

165
  return res.ok();
5✔
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