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

u-wave / core / 12200614762

06 Dec 2024 02:32PM UTC coverage: 84.144% (-0.2%) from 84.36%
12200614762

Pull #682

github

goto-bus-stop
Mimick session ID for JWT auth

The main point is to allow the tests to continue to use JWT auth,
while also testing session features such as missing messages for lost
connections
Pull Request #682: Improve session handling

906 of 1085 branches covered (83.5%)

Branch coverage included in aggregate %.

83 of 154 new or added lines in 11 files covered. (53.9%)

6 existing lines in 1 file now uncovered.

9867 of 11718 relevant lines covered (84.2%)

90.35 hits per line

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

75.46
/src/controllers/users.js
1
import {
1✔
2
  HTTPError,
1✔
3
  PermissionError,
1✔
4
  UserNotFoundError,
1✔
5
  UserNotInWaitlistError,
1✔
6
} from '../errors/index.js';
1✔
7
import skipIfCurrentDJ from '../utils/skipIfCurrentDJ.js';
1✔
8
import getOffsetPagination from '../utils/getOffsetPagination.js';
1✔
9
import toItemResponse from '../utils/toItemResponse.js';
1✔
10
import toListResponse from '../utils/toListResponse.js';
1✔
11
import toPaginatedResponse from '../utils/toPaginatedResponse.js';
1✔
12
import { muteUser, unmuteUser } from './chat.js';
1✔
13
import { REDIS_ACTIVE_SESSIONS } from '../SocketServer.js';
1✔
14

1✔
15
/**
1✔
16
 * @typedef {import('../schema').UserID} UserID
1✔
17
 */
1✔
18

1✔
19
/**
1✔
20
 * @typedef {object} GetUsersQuery
1✔
21
 * @prop {string} filter
1✔
22
 */
1✔
23

1✔
24
/**
1✔
25
 * @type {import('../types.js').AuthenticatedController<{}, GetUsersQuery>}
1✔
26
 */
1✔
27
async function getUsers(req) {
1✔
28
  const { filter } = req.query;
1✔
29
  const pagination = getOffsetPagination(req.query, {
1✔
30
    defaultSize: 50,
1✔
31
  });
1✔
32
  const { users } = req.uwave;
1✔
33

1✔
34
  const userList = await users.getUsers(filter, pagination);
1✔
35

1✔
36
  return toPaginatedResponse(userList, {
1✔
37
    baseUrl: req.fullUrl,
1✔
38
  });
1✔
39
}
1✔
40

1✔
41
/**
1✔
42
 * @typedef {object} GetUserParams
1✔
43
 * @prop {UserID} id
1✔
44
 */
1✔
45

1✔
46
/**
1✔
47
 * @type {import('../types.js').Controller<GetUserParams>}
1✔
48
 */
1✔
49
async function getUser(req) {
4✔
50
  const { users } = req.uwave;
4✔
51
  const { id: userID } = req.params;
4✔
52

4✔
53
  const user = await users.getUser(userID);
4✔
54
  if (!user) {
4!
55
    throw new UserNotFoundError({ id: userID });
×
56
  }
×
57

4✔
58
  return toItemResponse(user, {
4✔
59
    url: req.fullUrl,
4✔
60
  });
4✔
61
}
4✔
62

1✔
63
/**
1✔
64
 * @typedef {object} GetUserRolesParams
1✔
65
 * @prop {UserID} id
1✔
66
 */
1✔
67

1✔
68
/**
1✔
69
 * @type {import('../types.js').Controller<GetUserRolesParams>}
1✔
70
 */
1✔
71
async function getUserRoles(req) {
×
72
  const { acl, users } = req.uwave;
×
73
  const { id } = req.params;
×
74

×
75
  const user = await users.getUser(id);
×
76
  if (!user) {
×
77
    throw new UserNotFoundError({ id });
×
78
  }
×
79

×
80
  const roles = await acl.getAllPermissions(user);
×
81

×
82
  return toListResponse(roles, {
×
83
    url: req.fullUrl,
×
84
  });
×
85
}
×
86

1✔
87
/**
1✔
88
 * @typedef {object} AddUserRoleParams
1✔
89
 * @prop {UserID} id
1✔
90
 * @prop {string} role
1✔
91
 */
1✔
92

1✔
93
/**
1✔
94
 * @type {import('../types.js').AuthenticatedController<AddUserRoleParams>}
1✔
95
 */
1✔
96
async function addUserRole(req) {
3✔
97
  const { user: moderator } = req;
3✔
98
  const { id, role } = req.params;
3✔
99
  const { acl, users } = req.uwave;
3✔
100

3✔
101
  const canModifyRoles = moderator.roles.includes('admin');
3✔
102
  if (!canModifyRoles) {
3!
103
    throw new PermissionError({ requiredRole: 'admin' });
×
104
  }
×
105

3✔
106
  const user = await users.getUser(id);
3✔
107
  if (!user) {
3✔
108
    throw new UserNotFoundError({ id });
1✔
109
  }
1✔
110

2✔
111
  await acl.allow(user, [role]);
2✔
112

1✔
113
  return toItemResponse({}, {
1✔
114
    url: req.fullUrl,
1✔
115
  });
1✔
116
}
3✔
117

1✔
118
/**
1✔
119
 * @typedef {object} RemoveUserRoleParams
1✔
120
 * @prop {UserID} id
1✔
121
 * @prop {string} role
1✔
122
 */
1✔
123

1✔
124
/**
1✔
125
 * @type {import('../types.js').AuthenticatedController<RemoveUserRoleParams>}
1✔
126
 */
1✔
127
async function removeUserRole(req) {
2✔
128
  const { user: moderator } = req;
2✔
129
  const { id, role } = req.params;
2✔
130
  const { acl, users } = req.uwave;
2✔
131

2✔
132
  const canModifyRoles = moderator.roles.includes('admin');
2✔
133
  if (!canModifyRoles) {
2!
134
    throw new PermissionError({ requiredRole: 'admin' });
×
135
  }
×
136

2✔
137
  const user = await users.getUser(id);
2✔
138
  if (!user) {
2✔
139
    throw new UserNotFoundError({ id });
1✔
140
  }
1✔
141

1✔
142
  await acl.disallow(user, [role]);
1✔
143

1✔
144
  return toItemResponse({}, {
1✔
145
    url: req.fullUrl,
1✔
146
  });
1✔
147
}
2✔
148

1✔
149
/**
1✔
150
 * @typedef {object} ChangeUsernameParams
1✔
151
 * @prop {UserID} id
1✔
152
 * @typedef {object} ChangeUsernameBody
1✔
153
 * @prop {string} username
1✔
154
 */
1✔
155

1✔
156
/**
1✔
157
 * @type {import('../types.js').AuthenticatedController<
1✔
158
 *     ChangeUsernameParams, {}, ChangeUsernameBody>}
1✔
159
 */
1✔
160
async function changeUsername(req) {
5✔
161
  const { user: moderator } = req;
5✔
162
  const { id } = req.params;
5✔
163
  const { username } = req.body;
5✔
164
  const { users } = req.uwave;
5✔
165

5✔
166
  if (id !== moderator.id) {
5✔
167
    throw new PermissionError();
1✔
168
  }
1✔
169

4✔
170
  const user = await users.updateUser(
4✔
171
    id,
4✔
172
    { username },
4✔
173
    { moderator },
4✔
174
  );
4✔
175

3✔
176
  return toItemResponse(user);
3✔
177
}
5✔
178

1✔
179
/**
1✔
180
 * @returns {Promise<import('type-fest').JsonObject>}
1✔
181
 */
1✔
182
async function changeAvatar() {
×
183
  throw new HTTPError(500, 'Not implemented');
×
184
}
×
185

1✔
186
/**
1✔
187
 * Remove the user ID from the online users list.
1✔
188
 *
1✔
189
 * @param {import('../Uwave.js').default} uw
1✔
190
 * @param {UserID} userID
1✔
191
 */
1✔
192
async function disconnectUser(uw, userID) {
×
193
  await skipIfCurrentDJ(uw, userID);
×
194

×
195
  try {
×
196
    await uw.waitlist.removeUser(userID);
×
197
  } catch (err) {
×
198
    // It's expected that the user would not be in the waitlist
×
199
    if (!(err instanceof UserNotInWaitlistError)) {
×
200
      throw err;
×
201
    }
×
202
  }
×
203

×
NEW
204
  await uw.redis.lrem(REDIS_ACTIVE_SESSIONS, 0, userID);
×
205

×
206
  uw.publish('user:leave', { userID });
×
207
}
×
208

1✔
209
/**
1✔
210
 * @typedef {object} GetHistoryParams
1✔
211
 * @prop {UserID} id
1✔
212
 */
1✔
213

1✔
214
/**
1✔
215
 * @type {import('../types.js').Controller<GetHistoryParams>}
1✔
216
 */
1✔
217
async function getHistory(req) {
×
218
  const { id } = req.params;
×
219
  const pagination = getOffsetPagination(req.query, {
×
220
    defaultSize: 25,
×
221
    maxSize: 100,
×
222
  });
×
223
  const uw = req.uwave;
×
224

×
225
  const user = await uw.users.getUser(id);
×
226
  if (!user) {
×
227
    throw new UserNotFoundError({ id });
×
228
  }
×
229

×
230
  const history = await uw.history.getUserHistory(user, pagination);
×
231

×
232
  return toPaginatedResponse(history, {
×
233
    baseUrl: req.fullUrl,
×
234
    included: {
×
235
      media: ['media.media'],
×
236
      user: ['user'],
×
237
    },
×
238
  });
×
239
}
×
240

1✔
241
export {
1✔
242
  getUsers,
1✔
243
  getUser,
1✔
244
  getUserRoles,
1✔
245
  addUserRole,
1✔
246
  removeUserRole,
1✔
247
  changeUsername,
1✔
248
  changeAvatar,
1✔
249
  disconnectUser,
1✔
250
  getHistory,
1✔
251
  muteUser,
1✔
252
  unmuteUser,
1✔
253
};
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