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

statuscompliance / status-backend / 15768008471

19 Jun 2025 11:39PM UTC coverage: 84.933% (+3.3%) from 81.619%
15768008471

push

github

alvarobernal2412
test(catalog): added controller functions

870 of 1053 branches covered (82.62%)

Branch coverage included in aggregate %.

1 of 7 new or added lines in 1 file covered. (14.29%)

1740 of 2020 relevant lines covered (86.14%)

19.66 hits per line

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

81.25
/src/controllers/catalog.controller.js
1
import { models } from '../models/models.js';
2
import { storeGuaranteePoints } from '../utils/storeGuaranteePoints.js';
3
import registry from '../config/registry.js';
4
import { agreementBuilder } from '../utils/agreementBuilder.js';
5
import { v4 as uuidv4 } from 'uuid';
6
import _ from 'lodash';
7
import { finalizeControlsByCatalogId } from './control.controller.js';
8

9
export const getCatalogs = async (req, res) => {
52✔
10
  try {
3✔
11
    const { status } = req.query;
3✔
12
    
13
    let where = {};
3✔
14
    if (status === 'finalized' || status === 'draft') {
3✔
15
      where = { status };
1✔
16
    }
17
    
18
    const catalogs = await models.Catalog.findAll({ where });
3✔
19
    res.status(200).json(catalogs);
2✔
20
  } catch (error) {
21
    res.status(500).json({ message: `Failed to retrieve catalogs, error: ${error.message}` });
1✔
22
  }
23
};
24

25
export const getCatalog = async (req, res) => {
52✔
26
  try {
3✔
27
    const row = await models.Catalog.findByPk(req.params.id);
3✔
28

29
    if (!row) {
2✔
30
      return res.status(404).json({ message: 'Catalog not found' });
1✔
31
    }
32

33
    res.status(200).json(row);
1✔
34
  } catch (error) {
35
    res.status(500).json({ message: `Failed to retrieve catalog, error: ${error.message}` });
1✔
36
  }
37
};
38

39
export const createCatalog = async (req, res) => {
52✔
40
  try {
4✔
41
    const { name, description, startDate, endDate, dashboard_id, status } = req.body;
4✔
42
    if (!name || !startDate || !endDate) {
4✔
43
      return res.status(400).json({ message: 'Missing required fields: name, startDate, and/or endDate' });
1✔
44
    }
45
    const tpaId = status === 'draft' ? null : `tpa-${uuidv4()}`;
3✔
46
    const rows = await models.Catalog.create({
3✔
47
      name,
48
      description,
49
      startDate,
50
      endDate,
51
      dashboard_id,
52
      tpaId,
53
      status: status || 'finalized',
4✔
54
    });
55
    res.status(201).json(rows);
2✔
56
  } catch (error) {
57
    res.status(500).json({ message: `Failed to create catalog, error: ${error.message}` });
1✔
58
  }
59
};
60

61
export const updateCatalog = async (req, res) => {
52✔
62
  try {
4✔
63
    const { id } = req.params;
4✔
64
    const { name, description, startDate, endDate, dashboard_id, tpaId, status } = req.body;
4✔
65

66
    const currentCatalog = await models.Catalog.findByPk(id);
4✔
67
    if (!currentCatalog) {
4✔
68
      return res.status(404).json({ message: 'Catalog not found' });
1✔
69
    }
70

71
    // Prevent changing status from finalized to draft
72
    if (currentCatalog.status === 'finalized' && status === 'draft') {
3✔
73
      return res.status(400).json({ message: 'Cannot change status from finalized to draft' });
1✔
74
    }
75

76
    const updatedCatalog = await models.Catalog.update(
2✔
77
      {
78
        name,
79
        description,
80
        startDate,
81
        endDate,
82
        dashboard_id,
83
        tpaId,
84
        status,
85
      },
86
      {
87
        where: {
88
          id,
89
        },
90
        returning: true,
91
        plain: true,
92
      }
93
    );
94
    res.status(200).json(updatedCatalog[1]); // The first element is the number of affectedRows
1✔
95
  } catch (error) {
96
    res.status(500).json({ message: `Failed to update catalog, error: ${error.message}` });
1✔
97
  }
98
};
99

100
export const deleteCatalog = async (req, res) => {
52✔
101
  const result = await models.Catalog.destroy({
3✔
102
    where: {
103
      id: req.params.id,
104
    },
105
  });
106

107
  if (result <= 0)
2✔
108
    return res.status(404).json({
1✔
109
      message: 'Catalog not found',
110
    });
111

112
  res.sendStatus(204);
1✔
113
};
114

115
export async function calculatePoints(req, res) {
116
  try {
×
117
    const agreementId = req.params.tpaId;
×
118
    const { from, to } = req.query;
×
119

120
    // Validate agreementId format
NEW
121
    if (!/^tpa-[a-f0-9-]{36}$/.test(agreementId)) {
×
NEW
122
      return res.status(400).json({ message: 'Invalid agreementId format' });
×
123
    }
124

125
    const catalog = await models.Catalog.findOne({ where: {tpaId: agreementId}});
×
126
    const controls = await models.Control.findAll({where: {catalogId: catalog.id}});
×
127

128
    await updateOrCreateAgreement(catalog, controls, agreementId);
×
129

130
    // Construct the URL for fetching guarantees
NEW
131
    const basePath = 'api/v6/states/';
×
NEW
132
    const safeAgreementId = encodeURIComponent(agreementId);
×
NEW
133
    const url = `${basePath}${safeAgreementId}/guarantees`;
×
134

NEW
135
    const guaranteesStates = await registry.get(url, {
×
136
      params: { from, to, newPeriodsFromGuarantees: false },
137
      headers: { 'x-access-token': req.cookies.accessToken }
138
    });
139
    const { storedPoints, error } = await storeGuaranteePoints(guaranteesStates.data, agreementId);
×
140
    if (error.length > 0) {
×
141
      const points = await models.Point.findAll({where: {agreementId}});
×
142
      if (points.length > 0) {
×
143
        res.status(200).json(points);
×
144
      } else {
145
        res.status(400).json(error);
×
146
      }
147
    } else {
148
      res.status(200).json(storedPoints);
×
149
    }
150
  } catch (error) {
151
    res.status(500).json({
×
152
      message: `Failed to get points, error: ${error.message}`,
153
    });
154
  }
155
}
156

157
export async function updateOrCreateAgreement(catalog, controls, agreementId) {
158
  const agreement = await agreementBuilder(catalog, controls, { id: agreementId });
4✔
159
  try {
4✔
160
    const response = await registry.get(`api/v6/agreements/${agreementId}`);
4✔
161
    const oldAgreement = response.data;
2✔
162

163
    if (!_.isEqual(agreement, oldAgreement)) {
2✔
164
      console.log(`Updating agreement ${agreementId}`);
1✔
165
      await registry.put(`api/v6/agreements/${agreementId}`, agreement);
1✔
166
    }
167
  } catch (error) {
168
    if (error.response?.status === 404) {
2✔
169
      console.log(`Creating agreement ${agreementId}`);
1✔
170
      await registry.post('api/v6/agreements', agreement);
1✔
171
    } else {
172
      throw error; // Rethrow other errors
1✔
173
    }
174
  }
175
}
176

177
// Draft Catalogs
178

179
export const createDraftCatalog = async (req, res) => {
52✔
180
  try {
3✔
181
    const { name, description, startDate, endDate, dashboard_id } = req.body;
3✔
182
    if (!name || !startDate) {
3✔
183
      return res.status(400).json({ message: 'Missing required fields: name and/or startDate' });
1✔
184
    }
185
    
186
    const rows = await models.Catalog.create({
2✔
187
      name,
188
      description,
189
      startDate: startDate,
190
      endDate,
191
      dashboard_id,
192
      tpaId: null,
193
      status: 'draft',
194
    });
195
    res.status(201).json(rows);
1✔
196
  } catch (error) {
197
    res.status(500).json({ message: `Failed to create draft catalog, error: ${error.message}` });
1✔
198
  }
199
};
200

201
export const finalizeCatalog = async (req, res) => {
52✔
202
  try {
5✔
203
    const { id } = req.params;
5✔
204
    
205
    const currentCatalog = await models.Catalog.findByPk(id);
5✔
206
    if (!currentCatalog) {
5✔
207
      return res.status(404).json({ message: 'Catalog not found' });
1✔
208
    }
209
    
210
    if (currentCatalog.status !== 'draft') {
4✔
211
      return res.status(400).json({ message: 'Only draft catalogs can be finalized' });
1✔
212
    }
213
    
214
    if (!currentCatalog.startDate || !currentCatalog.endDate) {
3✔
215
      return res.status(400).json({ message: 'Catalog must have startDate and endDate to be finalized' });
1✔
216
    }
217
    
218
    const tpaId = `tpa-${uuidv4()}`;
2✔
219
    
220
    // First we update the catalog status and TPA ID
221
    const updatedCatalog = await models.Catalog.update(
2✔
222
      {
223
        status: 'finalized',
224
        tpaId,
225
      },
226
      {
227
        where: {
228
          id,
229
        },
230
        returning: true,
231
        plain: true,
232
      }
233
    );
234
    
235
    // Then we finalize the controls
236
    const controlsResult = await finalizeControlsByCatalogId(id);
1✔
237
    
238
    // Return the updated catalog and the number of finalized controls
239
    const finalizedCount = Array.isArray(controlsResult?.updated) ? controlsResult.updated.length : 0;
1!
240
    res.status(200).json({
1✔
241
      catalog: updatedCatalog[1],
242
      controls: {
243
        finalized: finalizedCount,
244
      }
245
    });
246
  } catch (error) {
247
    res.status(500).json({ message: `Failed to finalize catalog, error: ${error.message}` });
1✔
248
  }
249
};
250

251
export { finalizeControlsByCatalogId } from './control.controller.js';
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