meteor3: REST API async migration COMPLETE — smoke green on Meteor 3.1 + Mongo 7
All 12 Flutter REST endpoints byte-identical to the 1.6.1.1 baseline, running on Meteor 3.1 against dockerized MongoDB 7. The 3.x jump works end-to-end. - Rest.js: every endpoint action -> async; all Mongo calls -> *Async (findOneAsync/countAsync/fetchAsync/upsertAsync/removeAsync). - Helpers to async: countRealFires (accepts array|cursor, forEachAsync->for-of), firesUnion (fetchAsync), fireFromHash/findOrCreateFire (await, dropped Fibers Promise.await), subscriptionsInsert/subscriptionsRemove, upsertFalsePositive, falsePositives.insert, subscriptions.update method, countFiresInRegions. - getFires: countAsync() on a $near cursor throws on the mongodb 6 driver ($near not allowed in the aggregation countDocuments uses) -> fetch once and use array length for total. - Route order: json-routes 3.0 matches in registration order, so mobile/subscriptions/all/:token/:mobileToken is now registered BEFORE :token/:mobileToken/:subsId (else GET .../all/x/y hit the delete-only route).
This commit is contained in:
parent
b37069c3e5
commit
637a749e8d
6 changed files with 124 additions and 117 deletions
|
|
@ -29,40 +29,41 @@ const findFiresInRegion = (zone) => {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const countRealFires = (firesCursor) => {
|
export const countRealFires = async (firesCursor) => {
|
||||||
const realFires = [];
|
const realFires = [];
|
||||||
firesCursor.forEach((fire) => {
|
const fires = Array.isArray(firesCursor) ? firesCursor : await firesCursor.fetchAsync();
|
||||||
|
for (const fire of fires) {
|
||||||
if (debug) console.log(`${JSON.stringify(fire)} -----`);
|
if (debug) console.log(`${JSON.stringify(fire)} -----`);
|
||||||
const union = firesUnion([fire]);
|
const union = await firesUnion([fire]);
|
||||||
if (debug) console.log(`${JSON.stringify(union)} -----`);
|
if (debug) console.log(`${JSON.stringify(union)} -----`);
|
||||||
const falsePos = whichAreFalsePositives(FalsePositives, union);
|
const falsePos = whichAreFalsePositives(FalsePositives, union);
|
||||||
const industries = whichAreFalsePositives(Industries, union);
|
const industries = whichAreFalsePositives(Industries, union);
|
||||||
if (falsePos.count() === 0 && industries.count() === 0) {
|
if (await falsePos.countAsync() === 0 && await industries.countAsync() === 0) {
|
||||||
realFires.push(fire);
|
realFires.push(fire);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
// group fires
|
// group fires
|
||||||
const realUnion = firesUnion(realFires);
|
const realUnion = await firesUnion(realFires);
|
||||||
const unionCount = realUnion[0] &&
|
const unionCount = realUnion[0] &&
|
||||||
realUnion[0].geometry &&
|
realUnion[0].geometry &&
|
||||||
realUnion[0].geometry.coordinates ? realUnion[0].geometry.coordinates.length : 0;
|
realUnion[0].geometry.coordinates ? realUnion[0].geometry.coordinates.length : 0;
|
||||||
return unionCount;
|
return unionCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
const countFiresInRegions = (regions, stringsToRemove) => {
|
const countFiresInRegions = async (regions, stringsToRemove) => {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
const fireStats = {};
|
const fireStats = {};
|
||||||
|
|
||||||
regions.features.forEach((region) => {
|
for (const region of regions.features) {
|
||||||
const regionName = cleanProv(region.properties.name, stringsToRemove);
|
const regionName = cleanProv(region.properties.name, stringsToRemove);
|
||||||
const regionCode = region.properties.iso_a2;
|
const regionCode = region.properties.iso_a2;
|
||||||
if (debug) console.log(`${regionName} -----`);
|
if (debug) console.log(`${regionName} -----`);
|
||||||
try {
|
try {
|
||||||
const fires = findFiresInRegion(region);
|
const fires = findFiresInRegion(region);
|
||||||
// TODO Also check neighbour fires (when better implementation of that part)
|
// TODO Also check neighbour fires (when better implementation of that part)
|
||||||
const initialCount = fires.count();
|
const initialCount = await fires.countAsync();
|
||||||
if (initialCount > 0) {
|
if (initialCount > 0) {
|
||||||
const unionCount = countRealFires(fires);
|
const unionCount = await countRealFires(fires);
|
||||||
if (debug) console.log(`${regionName} initial: ${initialCount}, union calc: ${unionCount}`);
|
if (debug) console.log(`${regionName} initial: ${initialCount}, union calc: ${unionCount}`);
|
||||||
if (unionCount > 0) {
|
if (unionCount > 0) {
|
||||||
total += unionCount;
|
total += unionCount;
|
||||||
|
|
@ -72,7 +73,7 @@ const countFiresInRegions = (regions, stringsToRemove) => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ravenLogger.log(e);
|
ravenLogger.log(e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return { total, fires: fireStats };
|
return { total, fires: fireStats };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import FalsePositiveTypes from './FalsePositiveTypes';
|
||||||
import Fires from '../Fires/Fires';
|
import Fires from '../Fires/Fires';
|
||||||
import rateLimit from '../../modules/rate-limit';
|
import rateLimit from '../../modules/rate-limit';
|
||||||
|
|
||||||
export function upsertFalsePositive(keyType, owner, fire) {
|
export async function upsertFalsePositive(keyType, owner, fire) {
|
||||||
const fireType = fire.type;
|
const fireType = fire.type;
|
||||||
if (fireType === 'vecinal') {
|
if (fireType === 'vecinal') {
|
||||||
throw new Meteor.Error('500', 'No se puede marcar este tipo de fuego');
|
throw new Meteor.Error('500', 'No se puede marcar este tipo de fuego');
|
||||||
|
|
@ -22,7 +22,7 @@ export function upsertFalsePositive(keyType, owner, fire) {
|
||||||
fireId: fire._id,
|
fireId: fire._id,
|
||||||
geo: fire.ourid
|
geo: fire.ourid
|
||||||
};
|
};
|
||||||
return FalsePositives.upsert({ geo: fire.ourid, owner }, { $set: set }, { multi: false, upsert: true });
|
return await FalsePositives.upsertAsync({ geo: fire.ourid, owner }, { $set: set }, { multi: false, upsert: true });
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
console.log(exception);
|
console.log(exception);
|
||||||
throw new Meteor.Error('500', exception);
|
throw new Meteor.Error('500', exception);
|
||||||
|
|
@ -30,7 +30,7 @@ export function upsertFalsePositive(keyType, owner, fire) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Meteor.methods({
|
Meteor.methods({
|
||||||
'falsePositives.insert': function falsePositivesInsert(fireId, keyType) {
|
'falsePositives.insert': async function falsePositivesInsert(fireId, keyType) {
|
||||||
check(fireId, Meteor.Collection.ObjectID);
|
check(fireId, Meteor.Collection.ObjectID);
|
||||||
check(keyType, String);
|
check(keyType, String);
|
||||||
const type = FalsePositiveTypes[keyType];
|
const type = FalsePositiveTypes[keyType];
|
||||||
|
|
@ -39,10 +39,10 @@ Meteor.methods({
|
||||||
throw new Meteor.Error('500', 'Regístrate o inicia sesión para aportar información sobre este fuego');
|
throw new Meteor.Error('500', 'Regístrate o inicia sesión para aportar información sobre este fuego');
|
||||||
}
|
}
|
||||||
check(this.userId, String);
|
check(this.userId, String);
|
||||||
const fire = Fires.findOne(fireId);
|
const fire = await Fires.findOneAsync(fireId);
|
||||||
const owner = this.userId;
|
const owner = this.userId;
|
||||||
if (fire) {
|
if (fire) {
|
||||||
upsertFalsePositive(keyType, owner, fire);
|
await upsertFalsePositive(keyType, owner, fire);
|
||||||
} else {
|
} else {
|
||||||
throw new Meteor.Error('500', 'Fuego no encontrado');
|
throw new Meteor.Error('500', 'Fuego no encontrado');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ Meteor.publish('falsePositivesTotal', function total() {
|
||||||
return counter;
|
return counter;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const firesUnion = (fires) => {
|
export const firesUnion = async (fires) => {
|
||||||
const firesArray = Array.isArray(fires) ? fires : fires.fetch(); // if not is a cursor
|
const firesArray = Array.isArray(fires) ? fires : await fires.fetchAsync(); // if not is a cursor
|
||||||
const remap = firesArray.map(function remap(doc) {
|
const remap = firesArray.map(function remap(doc) {
|
||||||
const isNASA = doc.type === 'modis' || doc.type === 'viirs';
|
const isNASA = doc.type === 'modis' || doc.type === 'viirs';
|
||||||
const pixelSize = doc.type === 'viirs' ? 0.375 : 1; // viirs has 375m pixel size, modis 1000m
|
const pixelSize = doc.type === 'viirs' ? 0.375 : 1; // viirs has 375m pixel size, modis 1000m
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,12 @@ const fixConfidence = (obj) => {
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
const findOrCreateFire = (obj) => {
|
const findOrCreateFire = async (obj) => {
|
||||||
const fire = findFire(obj);
|
const fire = findFire(obj);
|
||||||
// console.log(`Found: ${fire.count()}`);
|
// console.log(`Found: ${await fire.countAsync()}`);
|
||||||
if (!obj.address) {
|
if (!obj.address) {
|
||||||
try {
|
try {
|
||||||
const rev = Promise.await(geocoder.reverse({ lat: obj.lat, lon: obj.lon }));
|
const rev = await geocoder.reverse({ lat: obj.lat, lon: obj.lon });
|
||||||
if (rev[0]) {
|
if (rev[0]) {
|
||||||
obj.address = rev[0].formattedAddress;
|
obj.address = rev[0].formattedAddress;
|
||||||
}
|
}
|
||||||
|
|
@ -67,10 +67,10 @@ const findOrCreateFire = (obj) => {
|
||||||
console.warn(reve);
|
console.warn(reve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fire.count() === 0) {
|
if (await fire.countAsync() === 0) {
|
||||||
// const result =
|
// const result =
|
||||||
// console.log('Creating new fire');
|
// console.log('Creating new fire');
|
||||||
FiresCollection.upsert({ ourid: obj.ourid, when: obj.when, type: obj.type }, { $set: obj }, { multi: false, upsert: true });
|
await FiresCollection.upsertAsync({ ourid: obj.ourid, when: obj.when, type: obj.type }, { $set: obj }, { multi: false, upsert: true });
|
||||||
// console.log(JSON.stringify(result));
|
// console.log(JSON.stringify(result));
|
||||||
}
|
}
|
||||||
return findFire(obj);
|
return findFire(obj);
|
||||||
|
|
@ -139,13 +139,12 @@ function logUrl(fireEnc, params) {
|
||||||
ravenLogger.log(message);
|
ravenLogger.log(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fireFromHash(fireEnc, params) {
|
export async function fireFromHash(fireEnc, params) {
|
||||||
check(fireEnc, String);
|
check(fireEnc, String);
|
||||||
check(params, Object);
|
check(params, Object);
|
||||||
|
|
||||||
// console.log(fireEnc);
|
// console.log(fireEnc);
|
||||||
// const unsealed = Promise.await(urlEnc.decrypt(fireEnc));
|
const unsealed = await unsealW(fireEnc);
|
||||||
const unsealed = Promise.await(unsealW(fireEnc));
|
|
||||||
if (unsealed === undefined) {
|
if (unsealed === undefined) {
|
||||||
throw Error(`Fail to unseal '${fireEnc}'`);
|
throw Error(`Fail to unseal '${fireEnc}'`);
|
||||||
}
|
}
|
||||||
|
|
@ -159,7 +158,7 @@ export function fireFromHash(fireEnc, params) {
|
||||||
// FIXME:
|
// FIXME:
|
||||||
const unsealedFix = fixConfidence(unsealed);
|
const unsealedFix = fixConfidence(unsealed);
|
||||||
FiresCollection.schema.validate(unsealedFix);
|
FiresCollection.schema.validate(unsealedFix);
|
||||||
return findOrCreateFire(unsealedFix);
|
return await findOrCreateFire(unsealedFix);
|
||||||
/* console.log(`fires: ${fire.count()}`);
|
/* console.log(`fires: ${fire.count()}`);
|
||||||
* return fire; */
|
* return fire; */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,8 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
},
|
},
|
||||||
endpoints: {
|
endpoints: {
|
||||||
get: {
|
get: {
|
||||||
action: function getFire() {
|
action: async function getFire() {
|
||||||
return Fires.findOne(new Meteor.Collection.ObjectID(this.urlParams.id));
|
return Fires.findOneAsync(new Meteor.Collection.ObjectID(this.urlParams.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,22 +98,22 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
|
|
||||||
// Maps to: /api/v1/status/last-fire-check
|
// Maps to: /api/v1/status/last-fire-check
|
||||||
apiV1.addRoute('status/last-fire-check', { authRequired: false }, {
|
apiV1.addRoute('status/last-fire-check', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
return SiteSettings.findOne({ name: 'last-fire-check' });
|
return SiteSettings.findOneAsync({ name: 'last-fire-check' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Maps to: /api/v1/status/last-fire-detected
|
// Maps to: /api/v1/status/last-fire-detected
|
||||||
apiV1.addRoute('status/last-fire-detected', { authRequired: false }, {
|
apiV1.addRoute('status/last-fire-detected', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
return ActiveFiresCollection.findOne({}, { sort: { when: -1 } });
|
return ActiveFiresCollection.findOneAsync({}, { sort: { when: -1 } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Maps to: /api/v1/status/active-fires-count
|
// Maps to: /api/v1/status/active-fires-count
|
||||||
apiV1.addRoute('status/active-fires-count', { authRequired: false }, {
|
apiV1.addRoute('status/active-fires-count', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
return { total: ActiveFiresCollection.find({}).count() };
|
return { total: await ActiveFiresCollection.find({}).countAsync() };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function getFires(route, full) {
|
async function getFires(route, full) {
|
||||||
const lat = Number(route.urlParams.lat);
|
const lat = Number(route.urlParams.lat);
|
||||||
const lng = Number(route.urlParams.lng);
|
const lng = Number(route.urlParams.lng);
|
||||||
const km = Number(route.urlParams.km);
|
const km = Number(route.urlParams.km);
|
||||||
|
|
@ -163,7 +163,11 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = { total: fires.count(), real: countRealFires(fires) };
|
// Meteor 3 / mongodb driver 6: countAsync() on a $near cursor fails
|
||||||
|
// ($near/$geoNear not allowed inside the aggregation countDocuments uses).
|
||||||
|
// Fetch once and derive the total from the array length instead.
|
||||||
|
const firesA = await fires.fetchAsync();
|
||||||
|
const result = { total: firesA.length, real: await countRealFires(firesA) };
|
||||||
if (debug) console.log(`Query for fires in ${lat}, ${lng} in ${km} km radius ${result}`);
|
if (debug) console.log(`Query for fires in ${lat}, ${lng} in ${km} km radius ${result}`);
|
||||||
|
|
||||||
if (!full) {
|
if (!full) {
|
||||||
|
|
@ -172,19 +176,16 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
|
|
||||||
let union;
|
let union;
|
||||||
|
|
||||||
// TODO only get real
|
|
||||||
const firesA = fires.fetch();
|
|
||||||
|
|
||||||
if (firesA.length > 0) {
|
if (firesA.length > 0) {
|
||||||
union = firesUnion(fires);
|
union = await firesUnion(firesA);
|
||||||
} else {
|
} else {
|
||||||
union = zoneToUnion(lat, lng, km);
|
union = zoneToUnion(lat, lng, km);
|
||||||
}
|
}
|
||||||
const falsePos = whichAreFalsePositives(FalsePositives, union);
|
const falsePos = whichAreFalsePositives(FalsePositives, union);
|
||||||
const industries = whichAreFalsePositives(Industries, union);
|
const industries = whichAreFalsePositives(Industries, union);
|
||||||
result.fires = firesA;
|
result.fires = firesA;
|
||||||
result.industries = industries.fetch();
|
result.industries = await industries.fetchAsync();
|
||||||
result.falsePos = falsePos.fetch();
|
result.falsePos = await falsePos.fetchAsync();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,13 +193,13 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
// 100 km max
|
// 100 km max
|
||||||
// Ex: http://127.0.0.1:3000/api/v1/fires-in/token/38.736946/-9.142685/100
|
// Ex: http://127.0.0.1:3000/api/v1/fires-in/token/38.736946/-9.142685/100
|
||||||
apiV1.addRoute('fires-in/:token/:lat/:lng/:km', { authRequired: false }, {
|
apiV1.addRoute('fires-in/:token/:lat/:lng/:km', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
return getFires(this, false);
|
return getFires(this, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
apiV1.addRoute('fires-in-full/:token/:lat/:lng/:km', { authRequired: false }, {
|
apiV1.addRoute('fires-in-full/:token/:lat/:lng/:km', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
return getFires(this, true);
|
return getFires(this, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -209,7 +210,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
//
|
//
|
||||||
// https://docs.meteor.com/api/passwords.html#Accounts-createUser
|
// https://docs.meteor.com/api/passwords.html#Accounts-createUser
|
||||||
apiV1.addRoute('mobile/users', { authRequired: false }, {
|
apiV1.addRoute('mobile/users', { authRequired: false }, {
|
||||||
post: function post() {
|
post: async function post() {
|
||||||
const { token, mobileToken, lang } = this.bodyParams;
|
const { token, mobileToken, lang } = this.bodyParams;
|
||||||
try {
|
try {
|
||||||
check(token, String);
|
check(token, String);
|
||||||
|
|
@ -225,22 +226,23 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
let username;
|
let username;
|
||||||
|
|
||||||
const already = Meteor.users.find({ fireBaseToken: mobileToken });
|
const already = Meteor.users.find({ fireBaseToken: mobileToken });
|
||||||
|
const alreadyCount = await already.countAsync();
|
||||||
|
|
||||||
if (already.count() > 1) {
|
if (alreadyCount > 1) {
|
||||||
return restivusError(500, 'Unexpected error in REST call: several users with that mobile token?');
|
return restivusError(500, 'Unexpected error in REST call: several users with that mobile token?');
|
||||||
} else if (already.count() === 1) {
|
} else if (alreadyCount === 1) {
|
||||||
username = already.fetch()[0].username;
|
username = (await already.fetchAsync())[0].username;
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
username = Random.id(15);
|
username = Random.id(15);
|
||||||
} while (Meteor.users.find({ username }).count() !== 0);
|
} while (await Meteor.users.find({ username }).countAsync() !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME check valid lang
|
// FIXME check valid lang
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
const result = Meteor.users.upsert({
|
const result = await Meteor.users.upsertAsync({
|
||||||
fireBaseToken: mobileToken
|
fireBaseToken: mobileToken
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
|
|
@ -260,7 +262,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
console.log(this.queryParams);
|
console.log(this.queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
const upsertUser = Meteor.users.findOne({ username });
|
const upsertUser = await Meteor.users.findOneAsync({ username });
|
||||||
|
|
||||||
if (debug) console.log(upsertUser);
|
if (debug) console.log(upsertUser);
|
||||||
|
|
||||||
|
|
@ -277,7 +279,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
|
|
||||||
// max sitance: 100km
|
// max sitance: 100km
|
||||||
apiV1.addRoute('mobile/subscriptions', { authRequired: false }, {
|
apiV1.addRoute('mobile/subscriptions', { authRequired: false }, {
|
||||||
post: function post() {
|
post: async function post() {
|
||||||
const {
|
const {
|
||||||
token,
|
token,
|
||||||
mobileToken,
|
mobileToken,
|
||||||
|
|
@ -305,7 +307,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
const failed = checkAuthToken(token);
|
const failed = checkAuthToken(token);
|
||||||
if (failed) return failed;
|
if (failed) return failed;
|
||||||
|
|
||||||
const user = Meteor.users.findOne({ fireBaseToken: mobileToken });
|
const user = await Meteor.users.findOneAsync({ fireBaseToken: mobileToken });
|
||||||
if (!user) return failMsg('User not found');
|
if (!user) return failMsg('User not found');
|
||||||
|
|
||||||
const newSubs = {};
|
const newSubs = {};
|
||||||
|
|
@ -317,7 +319,7 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
|
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = subscriptionsInsert(newSubs, user._id, 'mobile');
|
result = await subscriptionsInsert(newSubs, user._id, 'mobile');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return fail(e);
|
return fail(e);
|
||||||
}
|
}
|
||||||
|
|
@ -325,8 +327,57 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NOTE: json-routes 3.0 (Meteor 3) matches routes in registration order, so
|
||||||
|
// the literal `all/:token/:mobileToken` route MUST be registered before the
|
||||||
|
// `:token/:mobileToken/:subsId` route — otherwise a GET to
|
||||||
|
// `.../all/<tok>/<mob>` matches the 3-param route (delete-only) and restivus
|
||||||
|
// replies "API endpoint does not exist".
|
||||||
|
apiV1.addRoute('mobile/subscriptions/all/:token/:mobileToken', { authRequired: false }, {
|
||||||
|
get: async function get() {
|
||||||
|
const { token, mobileToken } = this.urlParams;
|
||||||
|
try {
|
||||||
|
check(token, String);
|
||||||
|
check(mobileToken, String);
|
||||||
|
} catch (e) {
|
||||||
|
return defaultFailParams(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const failed = checkAuthToken(token);
|
||||||
|
if (failed) return failed;
|
||||||
|
|
||||||
|
const user = await Meteor.users.findOneAsync({ fireBaseToken: mobileToken });
|
||||||
|
if (!user) return failMsg('User not found');
|
||||||
|
|
||||||
|
const result = Subscriptions.find({ owner: user._id });
|
||||||
|
|
||||||
|
return jsend.success({ subscriptions: await result.fetchAsync(), count: await result.countAsync() });
|
||||||
|
},
|
||||||
|
delete: async function delAll() {
|
||||||
|
const { token, mobileToken } = this.urlParams;
|
||||||
|
try {
|
||||||
|
check(token, String);
|
||||||
|
check(mobileToken, String);
|
||||||
|
} catch (e) {
|
||||||
|
return defaultFailParams(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const failed = checkAuthToken(token);
|
||||||
|
if (failed) return failed('Auth api check failed');
|
||||||
|
|
||||||
|
if (await Meteor.users.find({ fireBaseToken: mobileToken }).countAsync() !== 1) return fail;
|
||||||
|
|
||||||
|
const user = await Meteor.users.findOneAsync({ fireBaseToken: mobileToken });
|
||||||
|
if (!user) return failMsg('User not found');
|
||||||
|
|
||||||
|
const toRemove = await Subscriptions.find({ owner: user._id }).countAsync();
|
||||||
|
await Subscriptions.removeAsync({ owner: user._id });
|
||||||
|
|
||||||
|
return jsend.success({ count: toRemove });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
apiV1.addRoute('mobile/subscriptions/:token/:mobileToken/:subsId', { authRequired: false }, {
|
apiV1.addRoute('mobile/subscriptions/:token/:mobileToken/:subsId', { authRequired: false }, {
|
||||||
delete: function del() {
|
delete: async function del() {
|
||||||
const {
|
const {
|
||||||
token,
|
token,
|
||||||
mobileToken,
|
mobileToken,
|
||||||
|
|
@ -343,11 +394,11 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
const failed = checkAuthToken(token);
|
const failed = checkAuthToken(token);
|
||||||
if (failed) return failed;
|
if (failed) return failed;
|
||||||
|
|
||||||
const user = Meteor.users.findOne({ fireBaseToken: mobileToken });
|
const user = await Meteor.users.findOneAsync({ fireBaseToken: mobileToken });
|
||||||
if (!user) return failMsg('User not found');
|
if (!user) return failMsg('User not found');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Subscriptions.remove({ owner: user._id, _id: new Meteor.Collection.ObjectID(subsId) });
|
await Subscriptions.removeAsync({ owner: user._id, _id: new Meteor.Collection.ObjectID(subsId) });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return fail(e);
|
return fail(e);
|
||||||
}
|
}
|
||||||
|
|
@ -356,52 +407,8 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
apiV1.addRoute('mobile/subscriptions/all/:token/:mobileToken', { authRequired: false }, {
|
|
||||||
get: function get() {
|
|
||||||
const { token, mobileToken } = this.urlParams;
|
|
||||||
try {
|
|
||||||
check(token, String);
|
|
||||||
check(mobileToken, String);
|
|
||||||
} catch (e) {
|
|
||||||
return defaultFailParams(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const failed = checkAuthToken(token);
|
|
||||||
if (failed) return failed;
|
|
||||||
|
|
||||||
const user = Meteor.users.findOne({ fireBaseToken: mobileToken });
|
|
||||||
if (!user) return failMsg('User not found');
|
|
||||||
|
|
||||||
const result = Subscriptions.find({ owner: user._id });
|
|
||||||
|
|
||||||
return jsend.success({ subscriptions: result.fetch(), count: result.count() });
|
|
||||||
},
|
|
||||||
delete: function delAll() {
|
|
||||||
const { token, mobileToken } = this.urlParams;
|
|
||||||
try {
|
|
||||||
check(token, String);
|
|
||||||
check(mobileToken, String);
|
|
||||||
} catch (e) {
|
|
||||||
return defaultFailParams(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const failed = checkAuthToken(token);
|
|
||||||
if (failed) return failed('Auth api check failed');
|
|
||||||
|
|
||||||
if (Meteor.users.find({ fireBaseToken: mobileToken }).count() !== 1) return fail;
|
|
||||||
|
|
||||||
const user = Meteor.users.findOne({ fireBaseToken: mobileToken });
|
|
||||||
if (!user) return failMsg('User not found');
|
|
||||||
|
|
||||||
const toRemove = Subscriptions.find({ owner: user._id }).count();
|
|
||||||
Subscriptions.remove({ owner: user._id });
|
|
||||||
|
|
||||||
return jsend.success({ count: toRemove });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
apiV1.addRoute('status/subs-public-union/:token', { authRequired: false }, {
|
apiV1.addRoute('status/subs-public-union/:token', { authRequired: false }, {
|
||||||
get: function get() {
|
get: async function get() {
|
||||||
const { token } = this.urlParams;
|
const { token } = this.urlParams;
|
||||||
try {
|
try {
|
||||||
check(token, String);
|
check(token, String);
|
||||||
|
|
@ -412,15 +419,15 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
const failed = checkAuthToken(token);
|
const failed = checkAuthToken(token);
|
||||||
if (failed) return failed;
|
if (failed) return failed;
|
||||||
|
|
||||||
const currentUnion = SiteSettings.findOne({ name: 'subs-public-union' });
|
const currentUnion = await SiteSettings.findOneAsync({ name: 'subs-public-union' });
|
||||||
const userSubsBounds = SiteSettings.findOne({ name: 'subs-public-union-bounds' });
|
const userSubsBounds = await SiteSettings.findOneAsync({ name: 'subs-public-union-bounds' });
|
||||||
|
|
||||||
return jsend.success({ union: currentUnion, bounds: userSubsBounds });
|
return jsend.success({ union: currentUnion, bounds: userSubsBounds });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
apiV1.addRoute('mobile/falsepositive', { authRequired: false }, {
|
apiV1.addRoute('mobile/falsepositive', { authRequired: false }, {
|
||||||
post: function post() {
|
post: async function post() {
|
||||||
const {
|
const {
|
||||||
token,
|
token,
|
||||||
mobileToken,
|
mobileToken,
|
||||||
|
|
@ -440,15 +447,15 @@ if (!Meteor.settings.private.internalApiToken) {
|
||||||
const failed = checkAuthToken(token);
|
const failed = checkAuthToken(token);
|
||||||
if (failed) return failed;
|
if (failed) return failed;
|
||||||
|
|
||||||
const user = Meteor.users.findOne({ fireBaseToken: mobileToken });
|
const user = await Meteor.users.findOneAsync({ fireBaseToken: mobileToken });
|
||||||
if (!user) return failMsg('User not found');
|
if (!user) return failMsg('User not found');
|
||||||
|
|
||||||
console.log(`Marking hash fire as '${type}' false positive: ${sealed}`);
|
console.log(`Marking hash fire as '${type}' false positive: ${sealed}`);
|
||||||
const fireC = fireFromHash(sealed, { id: sealed });
|
const fireC = await fireFromHash(sealed, { id: sealed });
|
||||||
if (fireC && typeof fireC === 'object') {
|
if (fireC && typeof fireC === 'object') {
|
||||||
const fire = fireC.fetch()[0];
|
const fire = (await fireC.fetchAsync())[0];
|
||||||
console.log(`Marking fire as false positive: ${fire._id}`);
|
console.log(`Marking fire as false positive: ${fire._id}`);
|
||||||
const result = upsertFalsePositive(type, user._id, fire);
|
const result = await upsertFalsePositive(type, user._id, fire);
|
||||||
return jsend.success({ upsert: result });
|
return jsend.success({ upsert: result });
|
||||||
}
|
}
|
||||||
return failMsg('Cannot mark fire as false positive');
|
return failMsg('Cannot mark fire as false positive');
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ function geo(doc) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function subscriptionsInsert(doc, userId, type) {
|
export async function subscriptionsInsert(doc, userId, type) {
|
||||||
check(doc, {
|
check(doc, {
|
||||||
_id: Match.Maybe(Meteor.Collection.ObjectID),
|
_id: Match.Maybe(Meteor.Collection.ObjectID),
|
||||||
location: Match.ObjectIncluding({ lat: Number, lon: Number }),
|
location: Match.ObjectIncluding({ lat: Number, lon: Number }),
|
||||||
|
|
@ -23,23 +23,23 @@ export function subscriptionsInsert(doc, userId, type) {
|
||||||
...doc
|
...doc
|
||||||
};
|
};
|
||||||
// console.log(newDoc);
|
// console.log(newDoc);
|
||||||
const already = Subscriptions.findOne(newDoc);
|
const already = await Subscriptions.findOneAsync(newDoc);
|
||||||
if (already) {
|
if (already) {
|
||||||
throw new Meteor.Error('on-already-subscribed', 'The user is already subscribed to this area');
|
throw new Meteor.Error('on-already-subscribed', 'The user is already subscribed to this area');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Subscriptions.insert(newDoc);
|
return await Subscriptions.insertAsync(newDoc);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
// console.error(exception);
|
// console.error(exception);
|
||||||
throw new Meteor.Error('500', exception);
|
throw new Meteor.Error('500', exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function subscriptionsRemove(subscriptionId) {
|
export async function subscriptionsRemove(subscriptionId) {
|
||||||
check(subscriptionId, Meteor.Collection.ObjectID);
|
check(subscriptionId, Meteor.Collection.ObjectID);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Subscriptions.remove(subscriptionId);
|
return await Subscriptions.removeAsync(subscriptionId);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
console.error(exception);
|
console.error(exception);
|
||||||
throw new Meteor.Error('500', exception);
|
throw new Meteor.Error('500', exception);
|
||||||
|
|
@ -54,7 +54,7 @@ Meteor.methods({
|
||||||
});
|
});
|
||||||
return subscriptionsInsert(doc, this.userId, 'web');
|
return subscriptionsInsert(doc, this.userId, 'web');
|
||||||
},
|
},
|
||||||
'subscriptions.update': function subscriptionsUpdate(doc) {
|
'subscriptions.update': async function subscriptionsUpdate(doc) {
|
||||||
check(doc, {
|
check(doc, {
|
||||||
_id: Meteor.Collection.ObjectID,
|
_id: Meteor.Collection.ObjectID,
|
||||||
location: Match.ObjectIncluding({ lat: Number, lon: Number }),
|
location: Match.ObjectIncluding({ lat: Number, lon: Number }),
|
||||||
|
|
@ -65,7 +65,7 @@ Meteor.methods({
|
||||||
const dup = doc;
|
const dup = doc;
|
||||||
const subscriptionId = doc._id;
|
const subscriptionId = doc._id;
|
||||||
dup.geo = geo(doc);
|
dup.geo = geo(doc);
|
||||||
Subscriptions.update(subscriptionId, { $set: dup });
|
await Subscriptions.updateAsync(subscriptionId, { $set: dup });
|
||||||
return subscriptionId; // Return _id so we can redirect to subscription after update.
|
return subscriptionId; // Return _id so we can redirect to subscription after update.
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
throw new Meteor.Error('500', exception);
|
throw new Meteor.Error('500', exception);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue