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

GEWIS / sudosos-backend / 19907308868

03 Dec 2025 08:09PM UTC coverage: 89.583% (-0.2%) from 89.768%
19907308868

Pull #640

github

web-flow
Merge f3786a980 into fffd001d3
Pull Request #640: feat: notification abstraction

1528 of 1814 branches covered (84.23%)

Branch coverage included in aggregate %.

334 of 366 new or added lines in 22 files covered. (91.26%)

22 existing lines in 5 files now uncovered.

8009 of 8832 relevant lines covered (90.68%)

1051.65 hits per line

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

84.51
/src/controller/user-notification-preference-controller.ts
1
/**
2
 *  SudoSOS back-end API service.
3
 *  Copyright (C) 2024  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
 */
20

21
import BaseController, { BaseControllerOptions } from './base-controller';
2✔
22
import Policy from './policy';
23
import { RequestWithToken } from '../middleware/token-middleware';
24
import UserNotificationPreferenceService, {
2✔
25
  parseUserNotificationPreferenceFilters,
26
  UserNotificationPreferenceFilterParams,
27
} from '../service/user-notification-preference-service';
28
import { parseRequestPagination } from '../helpers/pagination';
2✔
29
import log4js, { Logger } from 'log4js';
2✔
30
import { Response } from 'express';
31
import UserNotificationPreference from '../entity/notifications/user-notification-preference';
2✔
32
import {
33
  UserNotificationPreferenceUpdateParams,
34
  UserNotificationPreferenceUpdateRequest,
35
} from './request/user-notification-preference-request';
36
import { asNumber } from '../helpers/validators';
2✔
37

38
/**
39
 * This is the module page of the notification-service.
40
 *
41
 * @module notifications
42
 *
43
 */
44

45
export default class UserNotificationController extends BaseController {
2✔
46
  /**
47
     * Reference to the logger instance
48
     */
49
  private logger: Logger = log4js.getLogger('UserNotificationPreferenceController');
2✔
50

51
  /**
52
     * Creates a new UserNotificationPreference controller instance
53
     * @param options - The options passed to the base controller.
54
     */
55
  public constructor(options: BaseControllerOptions) {
56
    super(options);
2✔
57
    this.logger.level = process.env.LOG_LEVEL;
2✔
58
  }
59

60
  /**
61
     * @inheritDoc
62
     */
63
  getPolicy(): Policy {
64
    return {
2✔
65
      '/': {
66
        GET: {
67
          policy: async (req) => this.roleManager.can(req.token.roles, 'get', await UserNotificationController.filterRelation(req), 'UserNotificationPreference', ['*']),
3✔
68
          handler: this.getAllUserNotificationPreferences.bind(this),
69
        },
70
      },
71
      '/:id(\\d+)': {
72
        GET: {
73
          policy: async (req) => this.roleManager.can(req.token.roles, 'get', await UserNotificationController.getRelation(req), 'UserNotificationPreference', ['*']),
4✔
74
          handler: this.getSingleUserNotificationPreference.bind(this),
75
        },
76
        PATCH: {
77
          policy: async (req) => this.roleManager.can(req.token.roles, 'update', await UserNotificationController.getRelation(req), 'UserNotificationPreference', ['*']),
4✔
78
          handler: this.updateUserNotificationPreference.bind(this),
79
        },
80
      },
81
    };
82
  }
83

84
  /**
85
     * GET /user-notification-preferences
86
     * @summary Returns all user notification preferences in the system.
87
     * @operationId getAllUserNotificationPreferences
88
     * @tags userNotificationPreferences - Operations of the user notification preference controller
89
     * @security JWT
90
     * @param {integer} userNotificationPreferenceId.query - Filter on the user notification preference id
91
     * @param {integer} userId.query - Filter on the user id
92
     * @param {string} type.query - Filter on the notification type
93
     * @param {string} channel.query - Filter on the notification channel
94
     * @param {boolean} enabled.query - Filter on enabled preferences
95
     * @return {PaginatedUserNotificationPreferenceResponse} 200 - All existing invoices
96
     * @return {string} 400 - Validation error
97
     * @return {string} 500 - Internal server error
98
     */
99
  public async getAllUserNotificationPreferences(req: RequestWithToken, res: Response): Promise<void> {
100
    const { body } = req;
3✔
101
    this.logger.trace('Get all user notification preferences', body, 'by user', req.token.user);
3✔
102

103
    let take;
104
    let skip;
105
    let filters: UserNotificationPreferenceFilterParams;
106

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

117
    try {
3✔
118
      const userNotificationPreferences = await new UserNotificationPreferenceService().getPaginatedUserNotificationPreference(
3✔
119
        filters, { take, skip },
120
      );
121
      res.json(userNotificationPreferences);
3✔
122
    } catch (e) {
NEW
123
      this.logger.error('Could not return all user notification preferences', e);
×
NEW
124
      res.status(500).json('Internal server error');
×
125
    }
126
  }
127

128
  /**
129
     * GET /user-notification-preferences/{id}
130
     * @summary Return a single user notification preferences in the system.
131
     * @operationId getSingleUserNotificationPreference
132
     * @tags userNotificationPreferences - Operations of the user notification preference controller
133
     * @security JWT
134
     * @param {integer} id.path.required - The id of the user notification preference
135
     * @return {BaseUserNotificationPreferenceResponse} 200 - The existing user notification preference
136
     * @return {string} 404 - User notification preference not found
137
     * @return {string} 500 - Internal server error
138
     */
139
  public async getSingleUserNotificationPreference(req: RequestWithToken, res: Response): Promise<void> {
140
    const { id } = req.params;
4✔
141
    const userNotificationPreferenceId = parseInt(id, 10);
4✔
142
    this.logger.trace('Get user notification preferences', userNotificationPreferenceId, 'by user', req.token.user);
4✔
143

144
    try {
4✔
145
      const userNotificationPreferences: UserNotificationPreference[] = await new UserNotificationPreferenceService().getUserNotificationPreferences(
4✔
146
        { userNotificationPreferenceId },
147
      );
148

149
      const userNotificationPreference = userNotificationPreferences[0];
4✔
150
      if (!userNotificationPreference) {
4✔
151
        res.status(404).send('Unknown user notification preference ID.');
1✔
152
        return;
1✔
153
      }
154

155
      const response = UserNotificationPreferenceService.asResponse(userNotificationPreference);
3✔
156

157
      res.json(response);
3✔
158
    } catch (e) {
NEW
159
      this.logger.error('Could not return user notification preferences', e);
×
NEW
160
      res.status(500).json('Internal server error');
×
161
    }
162
  }
163

164
  /**
165
     * PATCH /user-notification-preferences/{id}
166
     * @summary Update a user notification preferences in the system.
167
     * @operationId updateUserNotificationPreference
168
     * @tags userNotificationPreferences - Operations of the user notification preference controller
169
     * @security JWT
170
     * @param {integer} id.path.required - The id of the user notification preference
171
     * @param {UserNotificationPreferenceUpdateRequest} request.body.required -
172
     * The user notification preference update to process
173
     * @return {BaseUserNotificationPreferenceResponse} 200 - The existing user notification preference
174
     * @return {string} 404 - User notification preference not found
175
     * @return {string} 500 - Internal server error
176
     */
177
  public async updateUserNotificationPreference(req: RequestWithToken, res: Response): Promise<void> {
178
    const body  = req.body as UserNotificationPreferenceUpdateRequest;
4✔
179
    const { id } = req.params;
4✔
180
    const userNotificationPreferenceId = parseInt(id, 10);
4✔
181
    this.logger.trace('Update user notification preferences', userNotificationPreferenceId, 'by user', req.token.user);
4✔
182

183
    try {
4✔
184
      const params: UserNotificationPreferenceUpdateParams = {
4✔
185
        ...body,
186
        userNotificationPreferenceId,
187
      };
188

189
      const userNotificationPreference = await new UserNotificationPreferenceService().updateUserNotificationPreference(
4✔
190
        params,
191
      );
192

193
      if (!userNotificationPreference) {
4✔
194
        res.status(404).send('Unknown user notification preference ID.');
1✔
195
        return;
1✔
196
      }
197

198
      const response = UserNotificationPreferenceService.asResponse(userNotificationPreference);
3✔
199

200
      res.json(response);
3✔
201
    } catch (e) {
NEW
202
      this.logger.error('Could not update user notification preferences', e);
×
NEW
203
      res.status(500).json('Internal server error');
×
204
    }
205
  }
206

207
  /**
208
   * Determines the relation between the user and the notification preference.
209
   * - Returns own if user is connected to the notification preference
210
   * - Returns all otherwise.
211
   * @param req - Express request with user token and filters in query params.
212
   * @returns 'own' | 'all'
213
   */
214
  static async filterRelation(
215
    req: RequestWithToken,
216
  ): Promise<'own' | 'all'> {
217
    try {
3✔
218
      const reqUserId = req.token.user.id;
3✔
219
      const { userId } = parseUserNotificationPreferenceFilters(req);
3✔
220

221
      if (reqUserId == userId) {
3!
NEW
222
        return 'own';
×
223
      }
224

225
      return 'all';
3✔
226
    } catch (e) {
NEW
227
      return 'all';
×
228
    }
229
  }
230

231
  /**
232
   * Determines which credentials are needed to get user notification preferences
233
   *    all if user is not connected to user notification preference
234
   *    own if user is connected to the notification preference
235
   * @param req - Request with transaction id as param
236
   * @return whether transaction is connected to user token
237
   */
238
  static async getRelation(
239
    req: RequestWithToken,
240
  ): Promise<'all' | 'own'> {
241

242
    const preference = await UserNotificationPreference.findOne({
8✔
243
      where: { id: asNumber(req.params.id) },
244
      relations: ['user'],
245
    });
246

247
    if (!preference) return 'all';
8✔
248

249
    if (preference.userId == req.token.user.id) return 'own';
6✔
250

251
    return 'all';
4✔
252
  }
253
}
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