• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Info updated!

GEWIS / sudosos-backend / 25753937432

12 May 2026 09:17AM UTC coverage: 88.117% (-1.0%) from 89.089%
25753937432

push

github

web-flow
chore(deps): fix missing dependencies for running docs:dev (#911)

3925 of 4574 branches covered (85.81%)

Branch coverage included in aggregate %.

20093 of 22683 relevant lines covered (88.58%)

1125.83 hits per line

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

87.26
/src/controller/product-category-controller.ts
1
/**
1✔
2
 *  SudoSOS back-end API service.
3
 *  Copyright (C) 2026 Study association GEWIS
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU Affero General Public License as published
7
 *  by the Free Software Foundation, either version 3 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU Affero General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU Affero General Public License
16
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 *
18
 *  @license
19
 */
1✔
20

21
/**
1✔
22
 * This is the module page of product-category-controller.
23
 *
24
 * @module catalogue/product-categories
25
 */
1✔
26

27
import log4js, { Logger } from 'log4js';
28
import { Response } from 'express';
29
import BaseController, { BaseControllerOptions } from './base-controller';
30
import Policy from './policy';
31
import { RequestWithToken } from '../middleware/token-middleware';
32
import ProductCategoryService from '../service/product-category-service';
33
import ProductCategoryRequest from './request/product-category-request';
34
import { parseRequestPagination, toResponse } from '../helpers/pagination';
35

36
/**
1✔
37
 * Controller for managing all routes related to the `product category` entity.
38
 */
1✔
39
export default class ProductCategoryController extends BaseController {
1✔
40
  private logger: Logger = log4js.getLogger('ProductCategoryController');
1✔
41

42
  /**
1✔
43
     * Creates a new productcategory controller instance.
44
     * @param options - The options passed to the base controller.
45
     */
1✔
46
  public constructor(options: BaseControllerOptions) {
1✔
47
    super(options);
2✔
48
    this.configureLogger(this.logger);
2✔
49
  }
2✔
50

51
  /**
1✔
52
   * @inheritdoc
53
   */
1✔
54
  getPolicy(): Policy {
1✔
55
    return {
2✔
56
      '/': {
2✔
57
        GET: {
2✔
58
          policy: async (req) => this.roleManager.can(req.token.roles, 'get', 'all', 'ProductCategory', ['*']),
2✔
59
          handler: this.returnAllProductCategories.bind(this),
2✔
60
        },
2✔
61
        POST: {
2✔
62
          body: { modelName: 'ProductCategoryRequest' },
2✔
63
          policy: async (req) => this.roleManager.can(req.token.roles, 'create', 'all', 'ProductCategory', ['*']),
2✔
64
          handler: this.postProductCategory.bind(this),
2✔
65
        },
2✔
66
      },
2✔
67
      '/:id(\\d+)': {
2✔
68
        GET: {
2✔
69
          policy: async (req) => this.roleManager.can(req.token.roles, 'get', 'all', 'ProductCategory', ['*']),
2✔
70
          handler: this.returnSingleProductCategory.bind(this),
2✔
71
        },
2✔
72
        PATCH: {
2✔
73
          body: { modelName: 'ProductCategoryRequest' },
2✔
74
          policy: async (req) => this.roleManager.can(req.token.roles, 'update', 'all', 'ProductCategory', ['*']),
2✔
75
          handler: this.updateProductCategory.bind(this),
2✔
76
        },
2✔
77
      },
2✔
78
    };
2✔
79
  }
2✔
80

81
  /**
1✔
82
   * GET /productcategories
83
   * @summary Returns all existing productcategories
84
   * @operationId getAllProductCategories
85
   * @tags productCategories - Operations of productcategory controller
86
   * @security JWT
87
   * @param {boolean} onlyRoot.query - Whether to return only root categories
88
   * @param {boolean} onlyLeaf.query - Whether to return only leaf categories
89
   * @param {integer} take.query - How many product categories the endpoint should return
90
   * @param {integer} skip.query - How many product categories should be skipped (for pagination)
91
   * @return {PaginatedProductCategoryResponse} 200 - All existing productcategories
92
   * @return {string} 500 - Internal server error
93
   */
1✔
94
  public async returnAllProductCategories(req: RequestWithToken, res: Response): Promise<void> {
1✔
95
    const { body } = req;
5✔
96
    this.logger.trace('Get all productcategories', body, 'by user', req.token.user);
5✔
97

98
    let take;
5✔
99
    let skip;
5✔
100
    try {
5✔
101
      const pagination = parseRequestPagination(req);
5✔
102
      take = pagination.take;
5✔
103
      skip = pagination.skip;
5✔
104
    } catch (e) {
5!
105
      res.status(400).send(e.message);
×
106
      return;
×
107
    }
×
108

109
    // Handle request
5✔
110
    try {
5✔
111
      const [categories, count] = await ProductCategoryService
5✔
112
        .getProductCategories({
5✔
113
          onlyRoot: req.query.onlyRoot === 'true',
5✔
114
          onlyLeaf: req.query.onlyLeaf === 'true',
5✔
115
        }, { take, skip });
5✔
116
      res.json(toResponse(
5✔
117
        categories.map(ProductCategoryService.asProductCategoryResponse),
5✔
118
        count,
5✔
119
        { take, skip },
5✔
120
      ));
121
    } catch (error) {
5!
122
      this.logger.error('Could not return all product-categories:', error);
×
123
      res.status(500).json('Internal server error.');
×
124
    }
×
125
  }
5✔
126

127
  /**
1✔
128
   * POST /productcategories
129
   * @summary Post a new productCategory.
130
   * @operationId createProductCategory
131
   * @tags productCategories - Operations of productcategory controller
132
   * @param {ProductCategoryRequest} request.body.required
133
   * - The productCategory which should be created
134
   * @security JWT
135
   * @return {ProductCategoryResponse} 200 - The created productcategory entity
136
   * @return {string} 400 - Validation error
137
   * @return {string} 500 - Internal server error
138
   */
1✔
139
  public async postProductCategory(req: RequestWithToken, res: Response): Promise<void> {
1✔
140
    const body = req.body as ProductCategoryRequest;
5✔
141
    this.logger.trace('Create productcategory', body, 'by user', req.token.user);
5✔
142
    try {
5✔
143
      if (await ProductCategoryService.verifyProductCategory(body)) {
5✔
144
        const category = await ProductCategoryService.postProductCategory(body);
2✔
145
        res.json(ProductCategoryService.asProductCategoryResponse(category));
2✔
146
      } else {
5✔
147
        res.status(400).json('Invalid productcategory.');
3✔
148
      }
3✔
149
    } catch (error) {
5!
150
      this.logger.error('Could not create productcategory:', error);
×
151
      res.status(500).json('Internal server error.');
×
152
    }
×
153
  }
5✔
154

155
  /**
1✔
156
   * GET /productcategories/{id}
157
   * @summary Returns the requested productcategory
158
   * @operationId getSingleProductCategory
159
   * @tags productCategories - Operations of productcategory controller
160
   * @param {integer} id.path.required - The id of the productcategory which should be returned
161
   * @security JWT
162
   * @return {ProductCategoryResponse} 200 - The requested productcategory entity
163
   * @return {string} 404 - Not found error
164
   * @return {string} 500 - Internal server error
165
   */
1✔
166
  public async returnSingleProductCategory(req: RequestWithToken, res: Response): Promise<void> {
1✔
167
    const { id } = req.params;
3✔
168
    this.logger.trace('Get single productcategory', id, 'by user', req.token.user);
3✔
169

170
    // handle request
3✔
171
    try {
3✔
172
      // check if product in database
3✔
173
      const parsedId = parseInt(id, 10);
3✔
174
      const [categories] = await ProductCategoryService.getProductCategories({ id: parsedId });
3✔
175
      if (categories.length > 0) {
3✔
176
        res.json(ProductCategoryService.asProductCategoryResponse(categories[0]));
2✔
177
      } else {
3✔
178
        res.status(404).json('Productcategory not found.');
1✔
179
      }
1✔
180
    } catch (error) {
3!
181
      this.logger.error('Could not return productcategory:', error);
×
182
      res.status(500).json('Internal server error.');
×
183
    }
×
184
  }
3✔
185

186
  /**
1✔
187
   * PATCH /productcategories/{id}
188
   * @summary Update an existing productcategory.
189
   * @operationId updateProductCategory
190
   * @tags productCategories - Operations of productcategory controller
191
   * @param {integer} id.path.required - The id of the productcategory which should be returned
192
   * @param {ProductCategoryRequest} request.body.required
193
   * - The productcategory which should be created
194
   * @security JWT
195
   * @return {ProductCategoryResponse} 200 - The patched productcategory entity
196
   * @return {string} 400 - Validation error
197
   * @return {string} 404 - Not found error
198
   * @return {string} 500 - Internal server error
199
   */
1✔
200
  public async updateProductCategory(req: RequestWithToken, res: Response): Promise<void> {
1✔
201
    const body = req.body as ProductCategoryRequest;
3✔
202
    const { id } = req.params;
3✔
203
    this.logger.trace('Update productcategory', id, 'with', body, 'by user', req.token.user);
3✔
204

205
    // handle request
3✔
206
    try {
3✔
207
      if (await ProductCategoryService.verifyProductCategory(body)) {
3✔
208
        const parsedId = Number.parseInt(id, 10);
2✔
209
        const category = await ProductCategoryService.patchProductCategory(parsedId, body);
2✔
210
        if (category) {
2✔
211
          res.json(ProductCategoryService.asProductCategoryResponse(category));
1✔
212
        } else {
1✔
213
          res.status(404).json('Productcategory not found.');
1✔
214
        }
1✔
215
      } else {
3✔
216
        res.status(400).json('Invalid productcategory.');
1✔
217
      }
1✔
218
    } catch (error) {
3!
219
      this.logger.error('Could not update productcategory:', error);
×
220
      res.status(500).json('Internal server error.');
×
221
    }
×
222
  }
3✔
223
}
1✔
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