Skip to content

Commit a5403ef

Browse files
committed
Update Devices Page for Angular 14
1 parent 514fc7f commit a5403ef

21 files changed

+1808
-45
lines changed

service/src/models/device.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,41 @@ exports.getDeviceByUid = function (uid, { expand = {} } = {}) {
110110
return query.exec();
111111
};
112112

113-
exports.getDevices = function (options = {}) {
113+
exports.getDevices = async function (options = {}) {
114114
const { filter = {}, expand = {} } = options;
115-
116-
const conditions = createQueryConditions(filter);
115+
const { term, ...restFilter } = filter;
116+
117+
let conditions = createQueryConditions(restFilter);
118+
119+
if (term) {
120+
const regex = new RegExp(term, 'i');
121+
const base = Object.keys(conditions).length ? [conditions] : [];
122+
123+
// 🔹 Find users whose displayName matches the term
124+
const users = await User.Model
125+
.find({ displayName: regex })
126+
.select('_id')
127+
.lean()
128+
.exec();
129+
130+
const userIds = users.map(u => u._id);
131+
132+
// 🔹 Build OR condition over device fields + matching users
133+
const searchCondition = {
134+
$or: [
135+
{ uid: regex },
136+
{ name: regex },
137+
{ description: regex },
138+
...(userIds.length ? [{ userId: { $in: userIds } }] : [])
139+
]
140+
};
141+
142+
// Combine existing filters with search
143+
conditions = base.length
144+
? { $and: [...base, searchCondition] }
145+
: searchCondition;
146+
}
147+
117148

118149
let query = Device.find(conditions);
119150

@@ -130,7 +161,6 @@ exports.getDevices = function (options = {}) {
130161
query.populate('userId');
131162
}
132163
} else {
133-
// TODO is this minimum enough??
134164
query.populate({
135165
path: 'userId',
136166
select: 'displayName'

service/src/routes/devices.js

Lines changed: 147 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ const pageInfoTransformer = require('../transformers/pageinfo.js');
66
function DeviceResource() {}
77

88
module.exports = function(app, security) {
9-
109
var passport = security.authentication.passport;
1110
var resource = new DeviceResource(passport);
1211

1312
// DEPRECATED retain old routes as deprecated until next major version.
1413
/**
1514
* @deprecated
1615
*/
17-
app.post('/api/devices',
16+
app.post(
17+
'/api/devices',
1818
function authenticate(req, res, next) {
19-
log.warn('DEPRECATED - The /api/devices route will be removed in the next major version, please use /auth/{auth_strategy}/devices');
19+
log.warn(
20+
'DEPRECATED - The /api/devices route will be removed in the next major version, please use /auth/{auth_strategy}/devices'
21+
);
2022
passport.authenticate('local', function(err, user) {
2123
if (err) {
2224
return next(err);
@@ -44,12 +46,15 @@ module.exports = function(app, security) {
4446
if (!device) {
4547
device = await Device.createDevice(newDevice);
4648
}
47-
return res.json(device)
48-
}
49-
catch(err) {
49+
return res.json(device);
50+
} catch (err) {
5051
next(err);
5152
}
52-
next(new Error(`unknown error registering device ${newDevice.uid} for user ${newDevice.userId}`));
53+
next(
54+
new Error(
55+
`unknown error registering device ${newDevice.uid} for user ${newDevice.userId}`
56+
)
57+
);
5358
}
5459
);
5560

@@ -58,45 +63,51 @@ module.exports = function(app, security) {
5863
*
5964
* @deprecated Use /auth/{strategy}/authorize instead.
6065
*/
61-
app.post('/api/devices',
66+
app.post(
67+
'/api/devices',
6268
passport.authenticate('bearer'),
6369
resource.ensurePermission('CREATE_DEVICE'),
6470
resource.parseDeviceParams,
6571
resource.validateDeviceParams,
6672
resource.create
6773
);
6874

69-
app.get('/api/devices/count',
75+
app.get(
76+
'/api/devices/count',
7077
passport.authenticate('bearer'),
7178
access.authorize('READ_DEVICE'),
7279
resource.count
7380
);
7481

7582
// get all devices
76-
app.get('/api/devices',
83+
app.get(
84+
'/api/devices',
7785
passport.authenticate('bearer'),
7886
access.authorize('READ_DEVICE'),
7987
resource.getDevices
8088
);
8189

8290
// get device
8391
// TODO: check for READ_USER also
84-
app.get('/api/devices/:id',
92+
app.get(
93+
'/api/devices/:id',
8594
passport.authenticate('bearer'),
8695
access.authorize('READ_DEVICE'),
8796
resource.getDevice
8897
);
8998

9099
// Update a device
91-
app.put('/api/devices/:id',
100+
app.put(
101+
'/api/devices/:id',
92102
passport.authenticate('bearer'),
93103
access.authorize('UPDATE_DEVICE'),
94104
resource.parseDeviceParams,
95105
resource.updateDevice
96106
);
97107

98108
// Delete a device
99-
app.delete('/api/devices/:id',
109+
app.delete(
110+
'/api/devices/:id',
100111
passport.authenticate('bearer'),
101112
access.authorize('DELETE_DEVICE'),
102113
resource.deleteDevice
@@ -105,7 +116,9 @@ module.exports = function(app, security) {
105116

106117
DeviceResource.prototype.ensurePermission = function(permission) {
107118
return function(req, res, next) {
108-
access.userHasPermission(req.user, permission) ? next() : res.sendStatus(403);
119+
access.userHasPermission(req.user, permission)
120+
? next()
121+
: res.sendStatus(403);
109122
};
110123
};
111124

@@ -115,7 +128,9 @@ DeviceResource.prototype.ensurePermission = function(permission) {
115128
* @deprecated Use /auth/{strategy}/authorize instead.
116129
*/
117130
DeviceResource.prototype.create = function(req, res, next) {
118-
console.warn("Calling deprecated function to create device. Call authorize instead.");
131+
console.warn(
132+
'Calling deprecated function to create device. Call authorize instead.'
133+
);
119134

120135
// Automatically register any device created by an ADMIN
121136
req.newDevice.registered = true;
@@ -124,25 +139,31 @@ DeviceResource.prototype.create = function(req, res, next) {
124139
.then(device => {
125140
res.json(device);
126141
})
127-
.catch(err => {
128-
next(err)
142+
.catch(err => {
143+
next(err);
129144
});
130145
};
131146

132-
DeviceResource.prototype.count = function (req, res, next) {
147+
DeviceResource.prototype.count = function(req, res, next) {
133148
var filter = {};
134149

135-
if(req.query) {
150+
if (req.query) {
136151
for (let [key, value] of Object.entries(req.query)) {
137-
if(key == 'populate' || key == 'limit' || key == 'start' || key == 'sort' || key == 'forceRefresh'){
152+
if (
153+
key == 'populate' ||
154+
key == 'limit' ||
155+
key == 'start' ||
156+
key == 'sort' ||
157+
key == 'forceRefresh'
158+
) {
138159
continue;
139160
}
140161
filter[key] = value;
141162
}
142163
}
143164

144165
Device.count({ filter: filter })
145-
.then(count => res.json({count: count}))
166+
.then(count => res.json({ count: count }))
146167
.catch(err => next(err));
147168
};
148169

@@ -155,31 +176,119 @@ DeviceResource.prototype.count = function (req, res, next) {
155176
* this only actually supports a singular `expand` key, so why bother with
156177
* the split anyway?
157178
*/
158-
DeviceResource.prototype.getDevices = function (req, res, next) {
179+
DeviceResource.prototype.getDevices = async function (req, res, next) {
180+
try {
181+
const {
182+
populate,
183+
expand,
184+
limit,
185+
start,
186+
sort,
187+
includePagination,
188+
page,
189+
page_size,
190+
term,
191+
state,
192+
...rawFilter
193+
} = req.query;
194+
195+
const expandFlags = { user: /\buser\b/i.test(expand || '') };
196+
197+
const filter = {
198+
...rawFilter,
199+
...(term ? { term } : {}),
200+
...(state === 'registered'
201+
? { registered: 'true' }
202+
: state === 'unregistered'
203+
? { registered: 'false' }
204+
: {})
205+
};
206+
207+
let effectiveLimit;
208+
let effectiveStart;
209+
210+
const hasPageParams = page !== undefined || page_size !== undefined;
211+
212+
if (hasPageParams) {
213+
const pageNum = parseInt(page ?? '0', 10);
214+
const pageSizeNum = parseInt(page_size ?? '25', 10);
215+
216+
effectiveLimit = Number.isNaN(pageSizeNum) ? 25 : pageSizeNum;
217+
effectiveStart = (Number.isNaN(pageNum) ? 0 : pageNum) * effectiveLimit;
218+
} else {
219+
effectiveLimit = limit !== undefined ? parseInt(limit, 10) : undefined;
220+
effectiveStart = start !== undefined ? parseInt(start, 10) : undefined;
221+
}
159222

160-
const { populate, expand, limit, start, sort, forceRefresh, ...filter } = req.query;
161-
const expandFlags = { user: /\buser\b/i.test(expand) };
223+
const result = await Device.getDevices({
224+
filter,
225+
expand: expandFlags,
226+
limit: effectiveLimit,
227+
start: effectiveStart,
228+
sort
229+
});
162230

163-
Device.getDevices({ filter, expand: expandFlags, limit, start, sort })
164-
.then(result => {
165-
if (!Array.isArray(result)) {
166-
result = pageInfoTransformer.transform(result, req);
167-
}
168-
return res.json(result);
169-
})
170-
.catch(err => next(err));
231+
const shouldIncludePagination =
232+
includePagination &&
233+
String(includePagination).toLowerCase() !== 'false';
234+
235+
if (!shouldIncludePagination) {
236+
return res.json(result.items || result);
237+
}
238+
239+
const items = result.items || result;
240+
const totalCount =
241+
result.totalCount ??
242+
result.count ??
243+
(Array.isArray(items) ? items.length : 0);
244+
245+
let responsePageSize;
246+
let responsePage;
247+
248+
if (hasPageParams) {
249+
responsePageSize = effectiveLimit || 25;
250+
responsePage = Math.floor((effectiveStart || 0) / responsePageSize);
251+
} else {
252+
responsePageSize =
253+
result.pageSize ||
254+
effectiveLimit ||
255+
result.limit ||
256+
25;
257+
258+
responsePage =
259+
result.pageIndex ||
260+
result.page ||
261+
Math.floor((effectiveStart || 0) / responsePageSize);
262+
}
263+
264+
const pagePayload = {
265+
pageSize: responsePageSize,
266+
page: responsePage,
267+
totalCount,
268+
items
269+
};
270+
271+
return res.json(pagePayload);
272+
} catch (err) {
273+
next(err);
274+
}
171275
};
172276

277+
173278
DeviceResource.prototype.getDevice = function(req, res, next) {
174279
var expand = {};
175280
if (req.query.expand) {
176-
var expandList = req.query.expand.split(",");
177-
if (expandList.some(function(e) { return e === 'user';})) {
281+
var expandList = req.query.expand.split(',');
282+
if (
283+
expandList.some(function(e) {
284+
return e === 'user';
285+
})
286+
) {
178287
expand.user = true;
179288
}
180289
}
181290

182-
Device.getDeviceById(req.params.id, {expand: expand})
291+
Device.getDeviceById(req.params.id, { expand: expand })
183292
.then(device => res.json(device))
184293
.catch(err => next(err));
185294
};
@@ -189,7 +298,8 @@ DeviceResource.prototype.updateDevice = function(req, res, next) {
189298
if (req.newDevice.uid) update.uid = req.newDevice.uid;
190299
if (req.newDevice.name) update.name = req.newDevice.name;
191300
if (req.newDevice.description) update.description = req.newDevice.description;
192-
if (req.newDevice.registered !== undefined) update.registered = req.newDevice.registered;
301+
if (req.newDevice.registered !== undefined)
302+
update.registered = req.newDevice.registered;
193303
if (req.newDevice.userId) update.userId = req.newDevice.userId;
194304

195305
Device.updateDevice(req.param('id'), update)
@@ -199,7 +309,7 @@ DeviceResource.prototype.updateDevice = function(req, res, next) {
199309
res.json(device);
200310
})
201311
.catch(err => {
202-
next(err)
312+
next(err);
203313
});
204314
};
205315

service/src/utilities/paging.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function page(count, query, options, dataKey, dataConverter) {
3737
pageInfo.limit = limit;
3838
pageInfo[dataKey] = data;
3939
pageInfo.size = data.length;
40+
pageInfo.totalCount = count
4041

4142
const estimatedNext = start + limit;
4243

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export type Device = {
2+
uid?: string;
3+
registered?: boolean;
4+
appVersion?: string;
5+
userAgent?: string;
6+
id?: string;
7+
description?: string;
8+
user?: {
9+
displayName: string;
10+
id: string;
11+
}
12+
}

0 commit comments

Comments
 (0)