From 6d75b29edc4a25353f17b70101ad5e4ce5c8bc3f Mon Sep 17 00:00:00 2001 From: Chris Blanchard Date: Mon, 28 Dec 2015 13:21:35 +0000 Subject: [PATCH] Implemented basic messages api --- config/routes.js | 55 ++++++++++++---- db/models/message.js | 3 +- spec/messages.integration.js | 117 +++++++++++++++++++++++++++++++---- 3 files changed, 150 insertions(+), 25 deletions(-) diff --git a/config/routes.js b/config/routes.js index e599e03..3f2272d 100644 --- a/config/routes.js +++ b/config/routes.js @@ -1,10 +1,12 @@ "use strict"; -var path = require("path"); -var winston = require("winston"); -var config = require("./config.js"); -var Gather = require("../lib/gather/gather_singleton"); -var cors = require("cors"); +const path = require("path"); +const winston = require("winston"); +const config = require("./config.js"); +const Gather = require("../lib/gather/gather_singleton"); +const mongoose = require("mongoose"); +const Message = mongoose.model("Message"); +const cors = require("cors"); module.exports = app => { app.use(cors()); @@ -29,12 +31,43 @@ module.exports = app => { }); app.get("/messages", (request, response) => { - if (request.is("json")) { - // To Implement - response.end("") - } else { - response.render("messages.hbs"); - } + response.format({ + json: function() { + const limit = parseInt(request.query.limit, 10) || 250; + const page = parseInt(request.query.page, 10) || 0; + let query = {}; + let searchTerm = request.query.query; + if (searchTerm) { + query = { + $text: { + $search: searchTerm + } + }; + } + Message + .find(query) + .limit(limit) + .skip(page * limit) + .sort({createdAt: -1}) + .exec((error, messages) => { + if (error) { + winston.error(error); + return response.status(500).json({ + message: "An error occurred", + error: JSON.stringify(error) + }); + } + response.status(200).json({ + messages: messages, + page: page, + limit: limit + }); + }); + }, + default: function() { + response.render("messages.hbs"); + } + }) }); app.get("*", (request, response) => { diff --git a/db/models/message.js b/db/models/message.js index 523b2ad..0a692e9 100644 --- a/db/models/message.js +++ b/db/models/message.js @@ -15,8 +15,7 @@ var messageSchema = new Schema({ messageSchema.index({ createdAt: -1 }); messageSchema.index({ deleted: 1, createdAt: -1 }); - -// Instance Methods +messageSchema.index({ content: "text", "author.username": "text" }); messageSchema.methods.toJson = function () { return { diff --git a/spec/messages.integration.js b/spec/messages.integration.js index c57ca01..5f4d72f 100644 --- a/spec/messages.integration.js +++ b/spec/messages.integration.js @@ -1,33 +1,126 @@ "use strict"; -var helper = require("./helpers/index.js"); -var request = require("supertest"); -var assert = require("chai").assert; -var app = helper.app; +const async = require("async"); +const request = require("supertest"); +const assert = require("chai").assert; +const helper = require("./helpers/index.js"); +const Message = helper.Message; + +const app = helper.app; +let user, messages; describe("Messages", () => { + before(done => { + user = helper.createUser(); + helper.clearDb(done); + }); + beforeEach(done => { - done(); + messages = []; + async.timesSeries(6, (n, next) => { + Message.create({ + author: { + username: user.username, + avatar: user.avatar + }, + content: "Message " + n + }, (error, message) => { + if (error) return next(error); + messages.push(message); + next(); + }); + }, done); }); afterEach(done => { - done(); + helper.clearDb(done); }); + + describe("#Index", () => { describe("JSON Api", () => { - it ("returns most recent messages"); - it ("is sensitive to limit"); + it ("returns most recent messages", done => { + request(app) + .get("/messages") + .set("Accept", "application/json") + .expect("Content-Type", /json/) + .expect(200) + .end((error, response) => { + if (error) return done(error); + let result = response.body; + assert.equal(result.messages.length, 6); + assert.equal(result.limit, 250); + assert.equal(result.page, 0); + done(); + }); + }); + it ("is sensitive to limit", done => { + request(app) + .get("/messages") + .query({ + limit: 1 + }) + .set("Accept", "application/json") + .expect("Content-Type", /json/) + .expect(200) + .end((error, response) => { + if (error) return done(error); + let result = response.body; + assert.equal(result.messages.length, 1); + assert.equal(result.limit, 1); + assert.equal(result.page, 0); + assert.equal(result.messages[0].content, "Message 5"); + done(); + }); + }); it ("returns a maximum of last 250 messages"); - it ("is sensitive to pagination"); - it ("is sensitive to user"); - it ("is sensitive to search terms"); + it ("is sensitive to pagination", done => { + request(app) + .get("/messages") + .query({ + limit: 1, + page: 2 + }) + .set("Accept", "application/json") + .expect("Content-Type", /json/) + .expect(200) + .end((error, response) => { + if (error) return done(error); + let result = response.body; + assert.equal(result.messages.length, 1); + assert.equal(result.limit, 1); + assert.equal(result.page, 2); + assert.equal(result.messages[0].content, "Message 3"); + done(); + }); + }); + it ("is sensitive to search terms", done => { + request(app) + .get("/messages") + .query({ + query: "5" + }) + .set("Accept", "application/json") + .expect("Content-Type", /json/) + .expect(200) + .end((error, response) => { + if (error) return done(error); + let result = response.body; + assert.equal(result.messages.length, 1); + assert.equal(result.limit, 250); + assert.equal(result.page, 0); + assert.equal(result.messages[0].content, "Message 5"); + done(); + }); + }); }); + describe("HTML Browser", () => { it ("renders message browser", done => { request(app) .get("/messages") .set("Accept", "text/html; charset=utf-8") - .expect('Content-Type', /html/) + .expect("Content-Type", /html/) .expect(200) .end((error, response) => { if (error) return done(error);