├── .gitignore
├── .travis.yml
├── Dockerfile
├── README.md
├── app.js
├── docker-compose.yml
├── migrations
├── 1494711961629_create_chat_messages_table.js
├── 1494713525512_create_locations_table.js
├── 1494713602316_create_locations_archive_table.js
├── 1495574087854_create_gallery_table.js
└── 1505762006946_add_name_and_color.js
├── package.json
├── routes
├── debug.js
├── gallery.js
├── index.js
└── twitter.js
├── sql
├── retrieve_locations.sql
├── save_locations.sql
└── save_messages.sql
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 |
3 | services:
4 | - docker
5 |
6 | # Install non-default Docker Compose version
7 | before_install:
8 | - sudo rm /usr/local/bin/docker-compose
9 | - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
10 | - chmod +x docker-compose
11 | - sudo mv docker-compose /usr/local/bin
12 |
13 | install:
14 | - travis_retry docker build -t $DOCKER_IMAGE_NAME -f ./Dockerfile .
15 |
16 | script:
17 | - docker-compose -f docker-compose.yml up -d
18 | - docker-compose down
19 |
20 | env:
21 | global:
22 | - DOCKER_IMAGE_NAME=criticalmapsapi_web
23 | - DOCKER_COMPOSE_VERSION=1.12.0
24 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:6
2 |
3 | RUN apt-get update -y && \
4 | apt-get upgrade -y && \
5 | apt-get install -y git GraphicsMagick
6 |
7 | RUN mkdir -p /app/
8 | WORKDIR /app/
9 |
10 | RUN npm install -g node-pg-migrate pg --silent
11 |
12 | COPY package.json .
13 | RUN npm install
14 |
15 | COPY . .
16 |
17 | CMD npm start
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Critical Maps API
2 |
3 | [](https://travis-ci.org/criticalmaps/criticalmaps-api)
4 | [](https://codeclimate.com/github/criticalmaps/criticalmaps-api)
5 | [](https://codeclimate.com/github/criticalmaps/criticalmaps-api/coverage)
6 | [](https://gemnasium.com/criticalmaps/criticalmaps-api)
7 |
8 | ## Start development session with:
9 |
10 | ```docker-compose -f docker-compose.dev.yml up --build```
11 |
12 | ### Api will be available under:
13 | http://localhost:3000
14 |
15 | ### Debugger will be available at:
16 | http://localhost:8080/?port=5858
17 |
18 | ### phpPgAdmin is at:
19 | http://localhost:8082/phppgadmin/
20 |
21 | ## Migrations
22 |
23 | ```
24 | docker build -t criticalmaps-db-migrations -f Dockerfile.migrations . && \
25 | docker run \
26 | -v $(pwd)/migrations/:/migrations/ \
27 | -e DATABASE_URL=postgres://bla:bla@db/criticalmaps \
28 | criticalmaps-db-migrations \
29 | up
30 | ```
31 |
32 | docker exec -ti $(docker ps | grep postgres | awk '{ print $1}') /bin/bash
33 |
34 | psql -d criticalmaps -U bla
35 |
36 | ## TODO
37 | cors header??
38 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var pgp = require('pg-promise')();
3 | var bodyParser = require('body-parser');
4 |
5 |
6 | var app = express();
7 |
8 | // connect to databases
9 | postgres_db = pgp({
10 | host: process.env.POSTGRES_HOST,
11 | port: process.env.POSTGRES_PORT,
12 | database: process.env.POSTGRES_DB,
13 | user: process.env.POSTGRES_USER,
14 | password: process.env.POSTGRES_PASSWORD,
15 | poolSize: 8
16 | });
17 |
18 | app.set('port', 80);
19 |
20 | app.use(bodyParser.json({
21 | limit: '5mb'
22 | })); // Parses req.body json from html POST
23 | app.use(bodyParser.urlencoded({
24 | limit: '5mb',
25 | extended: true
26 | })); // Parses urlencoded req.body, including extended syntax
27 |
28 | // app.configure('development', function() {
29 | // app.use(express.logger('dev'));
30 | // app.use(express.errorHandler({
31 | // dumpExceptions: true,
32 | // showStack: true
33 | // }));
34 | // });
35 |
36 | app.use('/postv2', require('./routes/index'));
37 | app.use('/exchange', require('./routes/index'));
38 | app.use('/', require('./routes/index'));
39 |
40 | app.use('/twitter', require('./routes/twitter'));
41 | app.use('/twitter/get.php', require('./routes/twitter'));
42 |
43 | app.use('/gallery', require('./routes/gallery'));
44 |
45 | app.use('/debug', require('./routes/debug'));
46 |
47 |
48 | if (!module.parent) {
49 | app.listen(app.get('port'), function() {
50 | console.log('Server started on port ' + app.get('port'));
51 | })
52 | }
53 |
54 | module.exports = app;
55 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | db:
4 | image: postgres:9.6
5 | environment:
6 | POSTGRES_USER: bla
7 | POSTGRES_PASSWORD: bla
8 | POSTGRES_DB: criticalmaps
9 | ports:
10 | - "5433:5432"
11 | restart: always
12 |
13 | web:
14 | build:
15 | context: .
16 | dockerfile: Dockerfile
17 | ports:
18 | - "80:80"
19 | volumes:
20 | - .:/usr/src/app
21 | environment:
22 | NODE_ENV: production
23 | DEBUG: "*"
24 | DATABASE_URL: postgres://bla:bla@db:5433/criticalmaps
25 | links:
26 | - db
27 | restart: always
28 |
--------------------------------------------------------------------------------
/migrations/1494711961629_create_chat_messages_table.js:
--------------------------------------------------------------------------------
1 | var sql = `
2 | CREATE TABLE IF NOT EXISTS chat_messages (
3 | message text NOT NULL,
4 | ip inet NOT NULL,
5 | created timestamp NOT NULL default CURRENT_TIMESTAMP,
6 | identifier varchar(40) NOT NULL,
7 | longitude integer DEFAULT NULL,
8 | latitude integer DEFAULT NULL
9 | );
10 | `
11 |
12 | exports.up = (pgm) => {
13 | pgm.sql(sql)
14 | };
15 |
--------------------------------------------------------------------------------
/migrations/1494713525512_create_locations_table.js:
--------------------------------------------------------------------------------
1 | var sql = `
2 | CREATE TABLE IF NOT EXISTS locations (
3 | id SERIAL,
4 | device varchar(40) UNIQUE NOT NULL,
5 | updated timestamp NOT NULL default CURRENT_TIMESTAMP,
6 | longitude integer DEFAULT NULL,
7 | latitude integer DEFAULT NULL
8 | );
9 | `
10 |
11 | exports.up = (pgm) => {
12 | pgm.sql(sql)
13 | };
14 |
--------------------------------------------------------------------------------
/migrations/1494713602316_create_locations_archive_table.js:
--------------------------------------------------------------------------------
1 | var sql = `
2 | CREATE TABLE IF NOT EXISTS locations_archive (
3 | id SERIAL,
4 | device varchar(40) NOT NULL,
5 | created timestamp NOT NULL default CURRENT_TIMESTAMP,
6 | longitude integer DEFAULT NULL,
7 | latitude integer DEFAULT NULL
8 | );
9 | `
10 |
11 | exports.up = (pgm) => {
12 | pgm.sql(sql)
13 | };
14 |
--------------------------------------------------------------------------------
/migrations/1495574087854_create_gallery_table.js:
--------------------------------------------------------------------------------
1 | var sql = `
2 | CREATE TYPE review AS ENUM ('pending', 'aproved', 'rejected');
3 |
4 | CREATE TABLE IF NOT EXISTS gallery (
5 | id SERIAL,
6 | thumbnail bytea NOT NULL,
7 | image bytea NOT NULL,
8 | longitude integer DEFAULT NULL,
9 | latitude integer DEFAULT NULL,
10 | review_state review,
11 | ip inet NOT NULL
12 | );
13 | `
14 |
15 | exports.up = (pgm) => {
16 | pgm.sql(sql)
17 | };
18 |
--------------------------------------------------------------------------------
/migrations/1505762006946_add_name_and_color.js:
--------------------------------------------------------------------------------
1 | var sql = `
2 | ALTER TABLE locations ADD COLUMN name VARCHAR DEFAULT '';
3 | ALTER TABLE locations ADD COLUMN color varchar(6) DEFAULT NULL;
4 | `
5 |
6 | exports.up = (pgm) => {
7 | pgm.sql(sql)
8 | };
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "criticalmaps-api",
3 | "version": "0.0.0",
4 | "private": true,
5 | "main": "./app.js",
6 | "scripts": {
7 | "start": "pg-migrate up && node app.js",
8 | "test": "mocha test.js"
9 | },
10 | "dependencies": {
11 | "body-parser": "^1.17.1",
12 | "express": "^4.15.2",
13 | "form-data": "^2.2.0",
14 | "gm": "^1.23.0",
15 | "image-size": "^0.5.4",
16 | "moment": "^2.18.1",
17 | "multer": "^1.3.0",
18 | "pg-large-object": "^2.0.0",
19 | "pg-promise": "^5.6.7",
20 | "twitter": "^1.7.0"
21 | },
22 | "devDependencies": {
23 | "supertest-chai": "0.0.8",
24 | "chai-http": "^3.0.0",
25 | "chai": "^3.5.0",
26 | "mocha": "^3.3.0"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/routes/debug.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var os = require('os');
4 | var counter = 0;
5 |
6 | router.get('/', function(req, res, next) {
7 | var response = "";
8 | response += 'counter' + ' - ' + counter + '
';
9 | response += 'os.hostname()' + ' - ' + os.hostname() + '
';
10 | response += 'os.type()' + ' - ' + os.type() + '
';
11 | response += 'os.platform()' + ' - ' + os.platform() + '
';
12 | response += 'os.arch()' + ' - ' + os.arch() + '
';
13 | response += 'os.release()' + ' - ' + os.release() + '
';
14 | response += 'os.uptime()' + ' - ' + os.uptime() + '
';
15 | response += 'os.loadavg()' + ' - ' + os.loadavg() + '
'
16 | response += 'os.totalmem()' + ' - ' + os.totalmem() + '
';
17 | response += 'os.freemem()' + ' - ' + os.freemem() + '
';
18 | response += 'os.cpus()' + ' - ' + os.cpus().length + '
';
19 | response += 'os.networkInterfaces()' + ' - ' + os.networkInterfaces() + '
';
20 | console.log(response);
21 |
22 |
23 |
24 |
25 |
26 | res.send(response);
27 |
28 |
29 | counter++;
30 |
31 |
32 | });
33 |
34 | module.exports = router;
35 |
--------------------------------------------------------------------------------
/routes/gallery.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var debug = require('debug')('http');
4 | var QueryFile = require('pg-promise').QueryFile;
5 |
6 | var multer = require('multer');
7 | var upload = multer({
8 | dest: '/tmp/'
9 | })
10 | var sizeOf = require('image-size');
11 | var gm = require('gm');
12 | var fs = require('fs');
13 |
14 | var maxWidth = 100;
15 |
16 | var saveImage = function(req, res, next) {
17 | var pathImage = req.file.path;
18 | var pathThumbnail = req.file.path + "_thumb";
19 |
20 | var dimensions = sizeOf(pathImage);
21 |
22 | var oldWidth = dimensions.width
23 | var oldHeight = dimensions.height
24 |
25 | var newWidth = maxWidth;
26 | var newHeight = Math.floor(oldHeight * (maxWidth / oldWidth));
27 |
28 | gm(req.file.path)
29 | .resize(newWidth, newHeight)
30 | .noProfile()
31 | .write(pathThumbnail, function(err) {
32 | if (err) {
33 | return res.send("error " + err);
34 | }
35 | fs.readFile(pathImage, function(err, dataImage) {
36 | fs.readFile(pathThumbnail, function(err, dataThumbnail) {
37 | postgres_db.none('INSERT INTO gallery(image, thumbnail, review_state, ip, longitude, latitude) \
38 | VALUES($1, $2, $3, $4, $5, $6)', [dataImage, dataThumbnail, 'pending',
39 | req.connection.remoteAddress.replace(/^.*:/, ''),
40 | JSON.parse(req.body.data).longitude,
41 | JSON.parse(req.body.data).latitude
42 | ])
43 | .then(function() {
44 | res.send("success")
45 | // use http 200
46 | })
47 | .catch(function(error) {
48 | res.send("error: " + error)
49 | console.log(error)
50 |
51 | // use http code
52 | });
53 | });
54 | });
55 | });
56 | }
57 |
58 | router.post('/', upload.single('uploaded_file'), saveImage);
59 | router.post('/post.php', upload.single('uploaded_file'), saveImage);
60 |
61 | router.get('/', function(req, res, next) {
62 | res.setHeader('Access-Control-Allow-Origin', '*');
63 | postgres_db.any("SELECT id, longitude, latitude FROM gallery")
64 | .then(function(data) {
65 | res.send(data)
66 | })
67 | });
68 |
69 | router.get('/thumbnail/:id', function(req, res, next) {
70 | res.setHeader('Access-Control-Allow-Origin', '*');
71 | postgres_db.one("SELECT thumbnail FROM gallery WHERE id=$1", [req.params.id])
72 | .then(function(data) {
73 | console.log(data);
74 | res.writeHead(200, {
75 | 'Content-Type': 'image/jpeg'
76 | });
77 | res.write(data.thumbnail);
78 | res.end();
79 | })
80 | });
81 |
82 | router.get('/image/:id', function(req, res, next) {
83 | res.setHeader('Access-Control-Allow-Origin', '*');
84 | postgres_db.one("SELECT image FROM gallery WHERE id=$1", [req.params.id])
85 | .then(function(data) {
86 | console.log(data);
87 | res.writeHead(200, {
88 | 'Content-Type': 'image/jpeg'
89 | });
90 | res.write(data.image);
91 | res.end();
92 | });
93 | });
94 |
95 |
96 | module.exports = router;
97 |
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 | var debug = require('debug')('http');
4 | var QueryFile = require('pg-promise').QueryFile;
5 | var moment = require('moment')
6 |
7 | var QUERY_FILE_SAVE_LOCATIONS = QueryFile('sql/save_locations.sql')
8 | var QUERY_FILE_RETRIEVE_LOCATIONS = QueryFile('sql/retrieve_locations.sql')
9 | var QUERY_FILE_SAVE_MESSAGES = QueryFile('sql/save_messages.sql')
10 |
11 | var mainExchange = function(req, res, next) {
12 | res.setHeader('Access-Control-Allow-Origin', '*');
13 | postgres_db.tx(function(t1) {
14 | return t1.batch([
15 | save_messages_batch(req, t1),
16 | save_own_location_task(req, t1)
17 | ]);
18 | }).then(function(data_dont_care) {
19 | postgres_db.tx(function(t1) {
20 | return t1.batch([
21 | retrieve_other_locations(req, t1),
22 | retrieve_chat_messages(req, t1)
23 | ])
24 | }).then(function(data) {
25 | var response_obj = {
26 | locations: {},
27 | chatMessages: {}
28 | };
29 | data[0].forEach(function(location_obj) {
30 | response_obj.locations[location_obj.device] = {
31 | "longitude": location_obj.longitude,
32 | "latitude": location_obj.latitude,
33 | "timestamp": Math.floor(moment(location_obj.updated).valueOf() / 1000),
34 | "name": location_obj.name,
35 | "color": location_obj.color
36 | }
37 | });
38 |
39 | data[1].forEach(function(message_obj) {
40 | response_obj.chatMessages[message_obj.identifier] = {
41 | "message": message_obj.message,
42 | "timestamp": Math.floor(moment(message_obj.created).valueOf() / 1000)
43 | }
44 | });
45 | res.json(response_obj);
46 | }).catch(function(error) {
47 | handle_error(error, res)
48 | });
49 | })
50 | .catch(function(error) {
51 | handle_error(error, res)
52 | });
53 | }
54 |
55 | router.post('/', mainExchange);
56 | router.get('/', mainExchange);
57 | router.post('/postv2', mainExchange);
58 |
59 | var save_own_location_task = function(req, t) {
60 | if (req.body.hasOwnProperty("device") && req.body.hasOwnProperty("location")) {
61 | var longitude = req.body.location.longitude;
62 | var latitude = req.body.location.latitude;
63 | var device = req.body.device;
64 | var name = req.body.name;
65 | var color = req.body.color;
66 | return t.none(QUERY_FILE_SAVE_LOCATIONS, [device, longitude, latitude, name, color]);
67 | } else {
68 | return null;
69 | }
70 | }
71 |
72 | var retrieve_other_locations = function(req, t) {
73 | var device = req.body.device || "undefined";
74 | return t.any(QUERY_FILE_RETRIEVE_LOCATIONS, [device]);
75 | }
76 |
77 | var save_messages_batch = function(req, t) {
78 | if (!req.body.hasOwnProperty("messages")) {
79 | return null;
80 | }
81 |
82 | req.body.messages.sort(function(a, b) {
83 | return a.timestamp - b.timestamp;
84 | });
85 |
86 | var save_messages_batch = [];
87 | var delay_counter = 0;
88 | req.body.messages.forEach(function(message) {
89 | var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress.replace(/^.*:/, '');
90 | var latitude;
91 | var longitude;
92 |
93 | if (req.body.hasOwnProperty("location")) {
94 | latitude = req.body.location.latitude
95 | longitude = req.body.location.longitude
96 | }
97 |
98 | save_messages_batch.push(
99 | t.none(QUERY_FILE_SAVE_MESSAGES, [
100 | message.text,
101 | delay_counter,
102 | ip,
103 | message.identifier,
104 | longitude,
105 | latitude
106 | ])
107 | );
108 | delay_counter++;
109 | })
110 | return save_messages_batch;
111 | }
112 |
113 | var retrieve_chat_messages = function(req, t) {
114 | return t.any("SELECT * FROM chat_messages WHERE created > (NOW() - '$1 minutes'::INTERVAL)", [30]);
115 | }
116 |
117 | var handle_error = function(error, res) {
118 | console.log("ERROR:", error.message || error);
119 | res.status(500).json({
120 | error: error.message
121 | });
122 | }
123 |
124 | module.exports = router;
125 |
--------------------------------------------------------------------------------
/routes/twitter.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | var Twitter = require('twitter');
5 |
6 | var twitterClient = new Twitter({
7 | consumer_key: process.env.TWITTER_CONSUMER_KEY,
8 | consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
9 | access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
10 | access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
11 | });
12 |
13 | var twitterHandler = function(req, res, next) {
14 | console.log("foo")
15 |
16 | twitterClient.get('search/tweets', {
17 | q: 'criticalmaps',
18 | count: 100
19 | }, function(error, tweets, response) {
20 | if (!error) {
21 | res.json(tweets);
22 | } else {
23 | res.send(error);
24 | }
25 | });
26 | }
27 |
28 | router.get('/', twitterHandler);
29 | router.get('/get.php', twitterHandler);
30 |
31 | module.exports = router;
32 |
--------------------------------------------------------------------------------
/sql/retrieve_locations.sql:
--------------------------------------------------------------------------------
1 | -- delete locations older than 5 minutes
2 | DELETE
3 | FROM locations
4 | WHERE updated <= (CURRENT_TIMESTAMP - '5 minutes'::INTERVAL);
5 |
6 | -- get locations within the last 5 minutes &
7 | -- select the one with the highest timestamp for each device &
8 | -- ignore own device
9 | SELECT *
10 | FROM locations
11 | WHERE updated > (CURRENT_TIMESTAMP - '5 minutes'::INTERVAL)
12 | AND device != $1;
13 |
--------------------------------------------------------------------------------
/sql/save_locations.sql:
--------------------------------------------------------------------------------
1 | -- save own location
2 | -- if the device location already exists, override!
3 | INSERT INTO locations(device, longitude, latitude, name, color, updated)
4 | VALUES($1,
5 | $2,
6 | $3,
7 | $4,
8 | $5,
9 | CURRENT_TIMESTAMP) ON CONFLICT (device) DO
10 | UPDATE
11 | SET longitude = excluded.longitude,
12 | latitude = excluded.latitude,
13 | updated = CURRENT_TIMESTAMP;
14 |
15 | -- also save to locations archive
16 | -- INSERT INTO locations_archive(device, longitude, latitude)
17 | -- VALUES($1,
18 | -- $2,
19 | -- $3);
20 |
--------------------------------------------------------------------------------
/sql/save_messages.sql:
--------------------------------------------------------------------------------
1 | -- insert message only if the indentifier doesnt exist yet
2 | INSERT INTO chat_messages (message, created, ip, identifier, longitude, latitude)
3 | SELECT $1,
4 | now() + '$2 seconds'::INTERVAL,
5 | $3,
6 | $4,
7 | $5,
8 | $6
9 | WHERE NOT EXISTS
10 | ( SELECT *
11 | FROM chat_messages
12 | WHERE identifier = $4 )
13 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | var chai = require('chai');
2 | var chaiHttp = require('chai-http');
3 | var expect = chai.expect;
4 |
5 | chai.use(chaiHttp);
6 |
7 | var endpoint = "http://localhost:80";
8 |
9 | var test_user_A = {
10 | "device": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
11 | "location": {
12 | "longitude": 12345,
13 | "latitude": 54321
14 | }
15 | };
16 |
17 | var test_user_B_location_1 = {
18 | "device": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
19 | "location": {
20 | "longitude": 1,
21 | "latitude": 1
22 | }
23 | };
24 |
25 | var test_user_B_location_2 = {
26 | "device": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
27 | "location": {
28 | "longitude": 2,
29 | "latitude": 2
30 | }
31 | };
32 |
33 | describe('test location logic', function() {
34 | it('should not return own location', function(done) {
35 | chai.request(endpoint)
36 | .post('/')
37 | .send(test_user_A)
38 | .end(function(err, res) {
39 | expect(err).to.be.null;
40 | expect(res).to.have.status(200);
41 | expect(res).to.be.json;
42 | console.log(res.body)
43 | expect(res.body.locations).to.not.include.keys(test_user_A.device);
44 | done();
45 | });
46 | });
47 |
48 | it('should receive previous location from test user A', function(done) {
49 | chai.request(endpoint)
50 | .post('/')
51 | .send(test_user_B_location_1)
52 | .end(function(err, res) {
53 | expect(err).to.be.null;
54 | expect(res).to.have.status(200);
55 | expect(res).to.be.json;
56 | console.log(res.body)
57 | expect(res.body.locations[test_user_A.device])
58 | .to.deep.equal(test_user_A.location)
59 | done();
60 | });
61 | });
62 |
63 | it('should save new location test user B', function(done) {
64 | chai.request(endpoint)
65 | .post('/')
66 | .send(test_user_B_location_2)
67 | .end(function(err, res) {
68 | expect(err).to.be.null;
69 | expect(res).to.have.status(200);
70 | expect(res).to.be.json;
71 | done();
72 | });
73 | });
74 |
75 | it('should receive new location from test user B', function(done) {
76 | chai.request(endpoint)
77 | .post('/')
78 | .send(test_user_A)
79 | .end(function(err, res) {
80 | expect(err).to.be.null;
81 | expect(res).to.have.status(200);
82 | expect(res).to.be.json;
83 | expect(res.body.locations[test_user_B_location_1.device])
84 | .to.deep.equal(test_user_B_location_2.location)
85 | done();
86 | });
87 | });
88 |
89 |
90 | // describe('test messaging logic', function() {
91 | // it('should not return own location', function(done) {
92 | // chai.request('http://' + host + ':' + port)
93 | // .post('/')
94 | // .send(test_user_A)
95 | // .end(function(err, res) {
96 | // expect(err).to.be.null;
97 | // expect(res).to.have.status(200);
98 | // expect(res).to.be.json;
99 | // console.log(res.body)
100 | // expect(res.body.locations).to.not.include.keys(test_user_A.device);
101 | // done();
102 | // });
103 | // });
104 |
105 | });
106 |
--------------------------------------------------------------------------------