This commit is contained in:
Paul Bienkowski 2020-12-12 13:36:23 +01:00
parent 4a119a0fc9
commit b1271f4dd0
6 changed files with 178 additions and 2 deletions

View file

@ -54,6 +54,18 @@ const scan = (fn) =>
const flow = (...reducers) => (input) => reducers.reduce((c, fn) => fn(c), input);
function* zip(...iterables) {
const iterators = iterables.map((iterable) => iterable[Symbol.iterator]());
while (true) {
const results = iterators.map((iterator) => iterator.next());
if (results.some((r) => r.done)) {
return;
}
yield results.map((r) => r.value);
}
}
module.exports = {
filter,
map,
@ -62,4 +74,5 @@ module.exports = {
flow,
reduce,
scan,
zip,
};

35
src/models/PrivacyZone.js Normal file
View file

@ -0,0 +1,35 @@
const mongoose = require('mongoose');
const pointSchema = new mongoose.Schema({
type: {
type: String,
enum: ['Point'],
required: true,
},
coordinates: {
type: [Number],
required: true,
},
});
const schema = new mongoose.Schema(
{
center: {
type: pointSchema,
required: true,
},
radius: {
type: Number,
required: true,
},
name: String,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
},
{ timestamps: true },
);
class PrivacyZone extends mongoose.Model {}
mongoose.model(PrivacyZone, schema);
module.exports = PrivacyZone;

View file

@ -131,12 +131,15 @@ class Track extends mongoose.Model {
const trackData = TrackData.createFromPoints(points);
await trackData.save();
this.trackData = trackData._id;
if (this.visible) {
// TODO: create a distinct object with filtered data
this.publicTrackData = trackData._id;
const { author } = await this.populate('author').execPopulate();
const publicPoints = await author.privatizeTrackPoints(points);
const publicTrackData = TrackData.createFromPoints(publicPoints);
await publicTrackData.save();
this.publicTrackData = publicTrackData._id;
}
await this.save();

View file

@ -3,6 +3,9 @@ const uniqueValidator = require('mongoose-unique-validator');
const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const secret = require('../config').secret;
const turf = require('turf');
const { zip } = require('../_helpers/generators');
const PrivacyZone = require('./PrivacyZone');
const schema = new mongoose.Schema(
{
@ -84,6 +87,30 @@ class User extends mongoose.Model {
image: this.image || 'https://static.productionready.io/images/smiley-cyrus.jpg',
};
}
async privatizeTrackPoints(points) {
const privacyZones = await PrivacyZone.find({ user: this._id });
const centers = privacyZones.map((pz) => turf.point(pz.center.coordinates));
const radii = privacyZones.map((pz) => pz.radius);
const result = [];
for (const point of points) {
let skip = false;
const p = turf.point([point.longitude, point.latitude]);
for (const [center, radius] of zip(centers, radii)) {
const distanceMeters = turf.distance(p, center) * 1000
console.log(distanceMeters);
if (distanceMeters <= radius) {
skip = true;
break;
}
}
if (!skip) {
result.push(point);
}
}
return result;
}
}
mongoose.model(User, schema);

View file

@ -4,6 +4,7 @@ router.use('/', require('./users'));
router.use('/profiles', require('./profiles'));
router.use('/tracks', require('./tracks'));
router.use('/tags', require('./tags'));
router.use('/privacy-zones', require('./privacyZones'));
router.use('/accounts', require('../../accounts/accounts.controller'));
router.use(function (err, req, res, next) {

View file

@ -0,0 +1,97 @@
const router = require('express').Router();
const mongoose = require('mongoose');
const PrivacyZone = mongoose.model('PrivacyZone');
const busboy = require('connect-busboy');
const auth = require('../auth');
const wrapRoute = require('../../_helpers/wrapRoute');
function preloadByParam(target, getValueFromParam) {
return async (req, res, next, paramValue) => {
try {
const value = await getValueFromParam(paramValue);
if (!value) {
return res.sendStatus(404);
}
req[target] = value;
return next();
} catch (err) {
return next(err);
}
};
}
router.param(
'privacyZone',
preloadByParam('privacyZone', (id) => PrivacyZone.findOne({ _id: id }).populate('user')),
);
router.get(
'/',
auth.required,
wrapRoute(async (req, res) => {
const privacyZones = await PrivacyZone.find({ user: req.user._id });
return res.json({
privacyZones,
});
}),
);
router.post(
'/',
auth.required,
wrapRoute(async (req, res) => {
const privacyZone = new PrivacyZone(req.body);
privacyZone.user = req.user._id;
await privacyZone.save();
return res.json({ privacyZone });
}),
);
router.get(
'/:privacyZone',
auth.required,
wrapRoute(async (req, res) => {
if (!req.privacyZone.user._id.equals(req.user._id)) {
return res.sendStatus(403);
}
return res.json({ privacyZone: req.privacyZone });
}),
);
router.put(
'/:privacyZone',
busboy(),
auth.required,
wrapRoute(async (req, res) => {
if (!req.privacyZone.user._id.equals(req.user.id)) {
return res.sendStatus(403);
}
for (const key of ['center', 'radius', 'title']) {
if (key in req.body) {
req.privacyZone[key] = req.body[key]
}
}
return res.json({ privacyZone: req.privacyZone})
}),
);
router.delete(
'/:privacyZone',
auth.required,
wrapRoute(async (req, res) => {
if (!req.privacyZone.user._id.equals(req.user.id)) {
return res.sendStatus(403);
}
await req.privacyZone.remove();
return res.sendStatus(204);
}),
);
module.exports = router;