UNPKG

nightscout

Version:

Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.

119 lines (86 loc) 3.35 kB
'use strict'; const _ = require('lodash') , apiConst = require('../../const.json') , security = require('../../security') , validate = require('./validate.js') , opTools = require('../../shared/operationTools') , dateTools = require('../../shared/dateTools') , FieldsProjector = require('../../shared/fieldsProjector') ; /** * PATCH: Partially updates document in the collection */ async function patch (opCtx) { const { req, res, col } = opCtx; const doc = req.body; if (_.isEmpty(doc)) { return opTools.sendJSONStatus(res, apiConst.HTTP.BAD_REQUEST, apiConst.MSG.HTTP_400_BAD_REQUEST_BODY); } await security.demandPermission(opCtx, `api:${col.colName}:update`); col.parseDate(doc); const identifier = req.params.identifier , identifyingFilter = col.storage.identifyingFilter(identifier); const result = await col.storage.findOneFilter(identifyingFilter, { }); if (!result) throw new Error('result empty'); if (result.length > 0) { const storageDoc = result[0]; if (storageDoc.isValid === false) { return opTools.sendJSONStatus(res, apiConst.HTTP.GONE); } const modifiedDate = col.resolveDates(storageDoc) , ifUnmodifiedSince = req.get('If-Unmodified-Since'); if (ifUnmodifiedSince && dateTools.floorSeconds(modifiedDate) > dateTools.floorSeconds(new Date(ifUnmodifiedSince))) { return opTools.sendJSONStatus(res, apiConst.HTTP.PRECONDITION_FAILED); } await applyPatch(opCtx, identifier, doc, storageDoc); } else { return opTools.sendJSONStatus(res, apiConst.HTTP.NOT_FOUND); } } /** * Patch existing document in the collection * @param {Object} opCtx * @param {string} identifier * @param {Object} doc - fields and values to patch * @param {Object} storageDoc - original (database) version of document */ async function applyPatch (opCtx, identifier, doc, storageDoc) { const { ctx, res, col, auth } = opCtx; if (validate(opCtx, doc, storageDoc) !== true) return; const now = new Date; doc.srvModified = now.getTime(); if (auth && auth.subject && auth.subject.name) { doc.modifiedBy = auth.subject.name; } const matchedCount = await col.storage.updateOne(identifier, doc); if (!matchedCount) throw new Error('matchedCount empty'); res.setHeader('Last-Modified', now.toUTCString()); opTools.sendJSONStatus(res, apiConst.HTTP.OK); const fieldsProjector = new FieldsProjector('_all'); const patchedDocs = await col.storage.findOne(identifier, fieldsProjector); const patchedDoc = patchedDocs[0]; fieldsProjector.applyProjection(patchedDoc); ctx.bus.emit('storage-socket-update', { colName: col.colName, doc: patchedDoc }); col.autoPrune(); ctx.bus.emit('data-received'); } function patchOperation (ctx, env, app, col) { return async function operation (req, res) { const opCtx = { app, ctx, env, col, req, res }; try { opCtx.auth = await security.authenticate(opCtx); await patch(opCtx); } catch (err) { console.error(err); if (!res.headersSent) { return opTools.sendJSONStatus(res, apiConst.HTTP.INTERNAL_ERROR, apiConst.MSG.STORAGE_ERROR); } } }; } module.exports = patchOperation;