'use strict'; const User = require('../model/user'), LocCache = require('../model/location_cache'), ObjectId = require('mongodb').ObjectId, { UserTypes } = require('../helpers/constants'), queueHelper = require('../helpers/job_queue').getInstance(), utils = require('../helpers/utils'), geoUtils = require('../helpers/geo_util'), { Errors } = require('../helpers/constants'), { AppParamError, AppError } = require('../helpers/app_error'); /** * Find all user and vehicles/users last locations under the same user's applicator (excluding this user) * @returns last location list of { name, type, coors: [lat, lon], createdAt, updatedAt } */ async function nearMe_post(req, res) { const ops = req.body; const userId = ObjectId(req.uid); const isDevice = (req.ut === UserTypes.DEVICE); const user = await updateUserLoc({ uid: userId, kind: req.ut, coors: ops.coors || null }); const filter = { $and: [ { $or: [ { kind: { $ne: UserTypes.DEVICE }, _id: { $ne: userId } }, { kind: UserTypes.DEVICE, unitId: { $nin: [null, ''] } } ] } ] }; if (isDevice) { if (user.unitId) filter.$and[0].$or[1].unitId.$nin.push(user.unitId); filter.$and.push({ $or: [{ _id: user.parent }, { parent: (user.kind === UserTypes.APP ? userId : user.parent) }] }); } else { filter.$and.push({ $or: [{ _id: user.parent }, { parent: user.parent }] }); } const ulocs = await User.aggregate([ { $match: filter }, { $project: { _id: 0, unitId: { $cond: { if: { $ne: ["$kind", "9"] }, then: { $toString: "$_id" }, else: "$unitId" } }, name: { $cond: { if: { $ne: ["$kind", "9"] }, then: { $arrayElemAt: [{ $split: ["$username", "@"] }, 0] }, else: "$name" } }, type: { $cond: { if: { $ne: ["$kind", "9"] }, then: "user", else: "ac" } } } }, { $lookup: { from: "location_cache", localField: "unitId", foreignField: "unitId", as: "userLoc" } }, { $unwind: { path: "$userLoc" } }, { $project: { name: 1, type: 1, coors: ["$userLoc.lat", "$userLoc.lon"], createAt: { $toDate: "$userLoc._id" }, updatedAt: "$userLoc.updatedAt" } } ]); res.json(ulocs); } /** * Update user location, return the user detail if existed * @param {*} uloc User/Device location detail { uid: .., coors: [lat,lon], kind: userType } */ async function updateUserLoc(uloc) { let userStrId = uloc.uid.toHexString(); const user = await User.findOne({ _id: uloc.uid }, '-password', { lean: true }); if (user) { // Only log location if type is Device or Aircraft user account thus just update the user's latest location to location cache if (!utils.isEmptyArray(uloc.coors) && geoUtils.isValidLL(uloc.coors[0], uloc.coors[1])) { if (user.kind !== UserTypes.DEVICE || (user.kind === UserTypes.DEVICE && !user.unitId)) { const updateRessult = await LocCache.updateOne({ unitId: userStrId }, { $currentDate: { 'updatedAt': true, 'gdt': true }, $set: { lat: uloc.coors[0], lon: uloc.coors[1] } }, { upsert: true }); // Notify Track server to push the new added position for this user if (updateRessult && updateRessult.modifiedCount || updateRessult.upsertedCount) { const pkg = {}; pkg[userStrId] = [{ lat: utils.fixedTo(uloc.coors[0], 7), lon: utils.fixedTo(uloc.coors[1], 7), gdt: new Date() }]; queueHelper.publishLocTask(Buffer.from(JSON.stringify(pkg))); } } } return user; } else AppError.throw(Errors.USER_NOT_FOUND); } async function addpos_post(req, res) { const ops = req.body; if (!ops.coors) AppParamError.throw(); const uloc = await updateUserLoc({ uid: ObjectId(req.uid), kind: req.ut, coors: ops.coors }) res.json(uloc); } module.exports = { nearMe_post, addpos_post }