111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
import { BaseModel } from '#database/base_model'
|
|
import { DeviceRecord } from '../domain/device/device_record.js'
|
|
import { DeviceId } from '../domain/device/device_id.js'
|
|
import { DeviceComplianceInfo } from '../domain/configuration/compliance.js'
|
|
import { Filter, Sort } from 'mongodb'
|
|
|
|
export default class DeviceModel extends BaseModel {
|
|
static collectionName = 'devices'
|
|
|
|
static async findByIdentifier(identifier: string): Promise<DeviceRecord | null> {
|
|
return this.findOne({ identifier })
|
|
}
|
|
|
|
static async findByDeviceId(deviceId: DeviceId): Promise<DeviceRecord | null> {
|
|
return this.findOne({
|
|
'deviceId.manufacturer': deviceId.manufacturer,
|
|
'deviceId.oui': deviceId.oui,
|
|
'deviceId.productClass': deviceId.productClass,
|
|
'deviceId.serialNumber': deviceId.serialNumber,
|
|
})
|
|
}
|
|
|
|
static async paginateDevices(
|
|
offset: number,
|
|
limit: number,
|
|
filter: Filter<any> = {}
|
|
): Promise<{ data: DeviceRecord[]; total: number }> {
|
|
const collection = this.getCollection()
|
|
// Only return documents created by the ACS (must have an identifier field)
|
|
const safeFilter: Filter<any> = { ...filter, identifier: { $exists: true, $ne: null } }
|
|
const total = await collection.countDocuments(safeFilter)
|
|
const data = (await collection
|
|
.find(safeFilter, { projection: { _id: 0 } })
|
|
.skip(offset)
|
|
.limit(limit)
|
|
.sort({ updatedAt: -1 } as Sort)
|
|
.toArray()) as unknown as DeviceRecord[]
|
|
return { data, total }
|
|
}
|
|
|
|
static async distinctCriteriaValues(): Promise<{
|
|
manufacturers: string[]
|
|
ouis: string[]
|
|
productClasses: string[]
|
|
}> {
|
|
const collection = this.getCollection()
|
|
const [manufacturers, ouis, productClasses] = await Promise.all([
|
|
collection.distinct('deviceId.manufacturer'),
|
|
collection.distinct('deviceId.oui'),
|
|
collection.distinct('deviceId.productClass'),
|
|
])
|
|
return {
|
|
manufacturers: manufacturers.filter((v: any) => v && typeof v === 'string').sort(),
|
|
ouis: ouis.filter((v: any) => v && typeof v === 'string').sort(),
|
|
productClasses: productClasses.filter((v: any) => v && typeof v === 'string').sort(),
|
|
}
|
|
}
|
|
|
|
static async createOrUpdate(device: Partial<DeviceRecord>): Promise<DeviceRecord> {
|
|
const collection = this.getCollection()
|
|
let filter: Filter<any> = {}
|
|
|
|
if (device.deviceId) {
|
|
filter = { deviceId: device.deviceId }
|
|
} else if (device.identifier) {
|
|
filter = { identifier: device.identifier }
|
|
} else {
|
|
throw new Error('Either identifier or deviceId must be provided')
|
|
}
|
|
|
|
const result = await collection.findOneAndUpdate(
|
|
filter,
|
|
{
|
|
$set: { ...device, updatedAt: new Date() },
|
|
$setOnInsert: { createdAt: new Date() },
|
|
},
|
|
{ upsert: true, returnDocument: 'after', projection: { _id: 0 } }
|
|
)
|
|
|
|
return result as unknown as DeviceRecord
|
|
}
|
|
|
|
static async updateCompliance(
|
|
identifier: string,
|
|
compliance: DeviceComplianceInfo
|
|
): Promise<void> {
|
|
await this.updateOne({ identifier }, { compliance })
|
|
}
|
|
|
|
static async updateProvisioningCode(
|
|
identifier: string,
|
|
provisioningCode: string
|
|
): Promise<void> {
|
|
await this.updateOne({ identifier }, { provisioningCode })
|
|
}
|
|
|
|
static async resetComplianceForConfiguration(configurationIdentifier: string): Promise<void> {
|
|
const collection = this.getCollection()
|
|
await collection.updateMany(
|
|
{ 'compliance.configurationIdentifier': configurationIdentifier },
|
|
{
|
|
$set: {
|
|
'compliance.status': 'pending',
|
|
'compliance.lastError': null,
|
|
updatedAt: new Date(),
|
|
},
|
|
}
|
|
)
|
|
}
|
|
}
|