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

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

80.0
/src/controller/event-shift-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 event-shift-controller.
23
 *
24
 * @module events
25
 * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
26
 */
1✔
27

28
import BaseController, { BaseControllerOptions } from './base-controller';
29
import { Response } from 'express';
30
import log4js, { Logger } from 'log4js';
31
import Policy from './policy';
32
import { RequestWithToken } from '../middleware/token-middleware';
33
import EventService, { ShiftSelectedCountParams } from '../service/event-service';
34
import { EventShiftRequest } from './request/event-request';
35
import EventShift from '../entity/event/event-shift';
36
import { parseRequestPagination, toResponse } from '../helpers/pagination';
37
import { asDate, asEventType } from '../helpers/validators';
38

39
/**
1✔
40
 * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
41
 */
1✔
42
export default class EventShiftController extends BaseController {
1✔
43
  private logger: Logger = log4js.getLogger('EventShiftLogger');
1✔
44

45
  /**
1✔
46
   * Create a new user controller instance.
47
   * @param options - The options passed to the base controller.
48
   */
1✔
49
  public constructor(
1✔
50
    options: BaseControllerOptions,
2✔
51
  ) {
2✔
52
    super(options);
2✔
53
    this.configureLogger(this.logger);
2✔
54
  }
2✔
55

56
  public getPolicy(): Policy {
1✔
57
    return {
2✔
58
      '/': {
2✔
59
        GET: {
2✔
60
          policy: async (req) => this.roleManager.can(
2✔
61
            req.token.roles, 'get', 'all', 'Event', ['*'],
3✔
62
          ),
63
          handler: this.getAllShifts.bind(this),
2✔
64
        },
2✔
65
        POST: {
2✔
66
          policy: async (req) => this.roleManager.can(
2✔
67
            req.token.roles, 'create', 'all', 'Event', ['*'],
5✔
68
          ),
69
          handler: this.createShift.bind(this),
2✔
70
        },
2✔
71
      },
2✔
72
      '/:id(\\d+)': {
2✔
73
        PATCH: {
2✔
74
          policy: async (req) => this.roleManager.can(req.token.roles, 'update', 'all', 'Event', ['*']),
2✔
75
          handler: this.updateShift.bind(this),
2✔
76
        },
2✔
77
        DELETE: {
2✔
78
          policy: async (req) => this.roleManager.can(req.token.roles, 'delete', 'all', 'Event', ['*']),
2✔
79
          handler: this.deleteShift.bind(this),
2✔
80
        },
2✔
81
      },
2✔
82
      '/:id(\\d+)/counts': {
2✔
83
        GET: {
2✔
84
          policy: async (req) => this.roleManager.can(req.token.roles, 'update', 'all', 'Event', ['*']),
2✔
85
          handler: this.getShiftSelectedCount.bind(this),
2✔
86
        },
2✔
87
      },
2✔
88
    };
2✔
89
  }
2✔
90

91
  /**
1✔
92
   * GET /eventshifts
93
   * @summary Get all event shifts
94
   * @tags events - Operations of the event controller
95
   * @operationId getAllEventShifts
96
   * @security JWT
97
   * @param {integer} take.query - How many entries the endpoint should return
98
   * @param {integer} skip.query - How many entries should be skipped (for pagination)
99
   * @return {PaginatedEventShiftResponse} 200 - All existing event shifts
100
   * @return {string} 400 - Validation error
101
   * @return {string} 500 - Internal server error
102
   * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
103
   */
1✔
104
  public async getAllShifts(req: RequestWithToken, res: Response) {
1✔
105
    this.logger.trace('Get all shifts by user', req.token.user);
2✔
106

107
    let take;
2✔
108
    let skip;
2✔
109
    try {
2✔
110
      const pagination = parseRequestPagination(req);
2✔
111
      take = pagination.take;
2✔
112
      skip = pagination.skip;
2✔
113
    } catch (e) {
2!
114
      res.status(400).send(e.message);
×
115
      return;
×
116
    }
×
117

118
    try {
2✔
119
      const [shifts, count] = await EventService.getEventShifts({ take, skip });
2✔
120
      res.json(toResponse(shifts.map((s) => EventService.asEventShiftResponse(s)), count, { take, skip }));
2✔
121
    } catch (e) {
2!
122
      this.logger.error('Could not return all shifts:', e);
×
123
      res.status(500).json('Internal server error.');
×
124
    }
×
125
  }
2✔
126

127
  /**
1✔
128
   * POST /eventshifts
129
   * @summary Create an event shift
130
   * @tags events - Operations of the event controller
131
   * @operationId createEventShift
132
   * @security JWT
133
   * @param {CreateShiftRequest} request.body.required
134
   * @return {EventShiftResponse} 200 - Created event shift
135
   * @return {string} 400 - Validation error
136
   * @return {string} 500 - Internal server error
137
   * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
138
   */
1✔
139
  public async createShift(req: RequestWithToken, res: Response) {
1✔
140
    const body = req.body as EventShiftRequest;
4✔
141
    this.logger.trace('Create shift', body, 'by user', req.token.user);
4✔
142

143
    let params: EventShiftRequest;
4✔
144
    try {
4✔
145
      params = {
4✔
146
        name: req.body.name.toString(),
4✔
147
        roles: req.body.roles,
4✔
148
      };
4✔
149
      if (params.name === '' || !Array.isArray(params.roles)) {
4✔
150
        res.status(400).json('Invalid shift.');
2✔
151
        return;
2✔
152
      }
2✔
153
    } catch (e) {
4!
154
      res.status(400).json('Invalid shift.');
×
155
      return;
×
156
    }
✔
157

158
    // handle request
2✔
159
    try {
2✔
160
      res.json(await EventService.createEventShift(params));
2✔
161
    } catch (error) {
4!
162
      this.logger.error('Could not create event shift:', error);
×
163
      res.status(500).json('Internal server error.');
×
164
    }
×
165
  }
4✔
166

167
  /**
1✔
168
   * PATCH /eventshifts/{id}
169
   * @summary Update an event shift
170
   * @tags events - Operations of the event controller
171
   * @operationId updateEventShift
172
   * @security JWT
173
   * @param {integer} id.path.required - The id of the event which should be returned
174
   * @param {UpdateShiftRequest} request.body.required
175
   * @return {EventShiftResponse} 200 - Created event shift
176
   * @return {string} 400 - Validation error
177
   * @return {string} 500 - Internal server error
178
   * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
179
   */
1✔
180
  public async updateShift(req: RequestWithToken, res: Response) {
1✔
181
    const { id: rawId } = req.params;
4✔
182
    const body = req.body as EventShiftRequest;
4✔
183
    this.logger.trace('Update shift', rawId, 'with body', body, 'by user', req.token.user);
4✔
184

185
    let id = Number.parseInt(rawId, 10);
4✔
186
    try {
4✔
187
      const shift = await EventShift.findOne({ where: { id } });
4✔
188
      if (shift == null) {
4!
189
        res.status(404).send();
×
190
        return;
×
191
      }
×
192
    } catch (error) {
4!
193
      this.logger.error('Could not update event:', error);
×
194
      res.status(500).json('Internal server error.');
×
195
    }
×
196

197
    let param: Partial<EventShiftRequest>;
4✔
198
    try {
4✔
199
      param = {
4✔
200
        name: req.body.name?.toString(),
4✔
201
        roles: req.body.roles,
4✔
202
      };
4✔
203
      if (param.name === '' || (param.roles !== undefined && !Array.isArray(param.roles))) {
4✔
204
        res.status(400).json('Invalid shift.');
2✔
205
        return;
2✔
206
      }
2✔
207
    } catch (e) {
4!
208
      res.status(400).json('Invalid shift.');
×
209
      return;
×
210
    }
✔
211

212
    // handle request
2✔
213
    try {
2✔
214
      res.json(await EventService.updateEventShift(id, param));
2✔
215
    } catch (error) {
4!
216
      this.logger.error('Could not update event shift:', error);
×
217
      res.status(500).json('Internal server error.');
×
218
    }
×
219
  }
4✔
220

221
  /**
1✔
222
   * DELETE /eventshifts/{id}
223
   * @summary Delete an event shift with its answers
224
   * @tags events - Operations of the event controller
225
   * @operationId deleteEventShift
226
   * @security JWT
227
   * @param {integer} id.path.required - The id of the event which should be deleted
228
   * @return 204 - Success
229
   * @return {string} 400 - Validation error
230
   * @return {string} 500 - Internal server error
231
   * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
232
   */
1✔
233
  public async deleteShift(req: RequestWithToken, res: Response) {
1✔
234
    const { id: rawId } = req.params;
2✔
235
    this.logger.trace('Delete shift with ID', rawId, 'by user', req.token.user);
2✔
236

237
    try {
2✔
238
      const id = Number.parseInt(rawId, 10);
2✔
239
      const shift = await EventShift.findOne({ where: { id }, withDeleted: true });
2✔
240
      if (shift == null) {
2✔
241
        res.status(404).send();
1✔
242
        return;
1✔
243
      }
1✔
244

245
      await EventService.deleteEventShift(id);
1✔
246
      res.status(204).send();
1✔
247
    } catch (error) {
2!
248
      this.logger.error('Could not delete event shift:', error);
×
249
      res.status(500).json('Internal server error.');
×
250
    }
×
251
  }
2✔
252

253
  /**
1✔
254
   * GET /eventshifts/{id}/counts
255
   * @summary Get the number of times a user has been selected for the given shift
256
   * @tags events - Operations of the event controller
257
   * @operationId getEventShiftCount
258
   * @security JWT
259
   * @param {integer} id.path.required - The id of the event shift
260
   * @param {string} eventType.query - Only include events of this type
261
   * @param {string} afterDate.query - Only include events after this date
262
   * @param {string} beforeDate.query - Only include events before this date
263
   * @return {Array<PaginatedEventShiftResponse>} 200 - All existing event shifts
264
   * @return {string} 400 - Validation error
265
   * @return {string} 500 - Internal server error
266
   * @deprecated Events are out of scope for SudoSOS. Delete from 01/11/2026.
267
   */
1✔
268
  public async getShiftSelectedCount(req: RequestWithToken, res: Response) {
1✔
269
    const { id: rawId } = req.params;
10✔
270
    this.logger.trace('Delete shift with ID', rawId, 'by user', req.token.user);
10✔
271

272
    try {
10✔
273
      const id = Number.parseInt(rawId, 10);
10✔
274
      const shift = await EventShift.findOne({ where: { id } });
10✔
275
      if (shift == null) {
10✔
276
        res.status(404).send();
1✔
277
        return;
1✔
278
      }
1✔
279

280
      let params: ShiftSelectedCountParams;
9✔
281
      try {
9✔
282
        params = {
9✔
283
          eventType: asEventType(req.query.eventType),
9✔
284
          afterDate: asDate(req.query.afterDate),
9✔
285
          beforeDate: asDate(req.query.beforeDate),
9✔
286
        };
9✔
287
      } catch (e) {
10!
288
        res.status(400).send(e.message);
×
289
        return;
×
290
      }
✔
291

292
      const counts = await EventService.getShiftSelectedCount(id, params);
9✔
293
      res.json(counts);
9✔
294
    } catch (error) {
10!
295
      this.logger.error('Could not get event shift counts:', error);
×
296
      res.status(500).json('Internal server error.');
×
297
    }
×
298
  }
10✔
299
}
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