mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-05 19:01:03 +00:00
Add endpoints for resolving and reopening threads
This commit is contained in:
parent
cb88e1e41b
commit
1ff920e1b5
9 changed files with 190 additions and 34 deletions
|
@ -16,17 +16,31 @@ module.exports = MessageFormatter =
|
|||
(@formatMessageForClientSide(message) for message in messages)
|
||||
|
||||
groupMessagesByThreads: (rooms, messages) ->
|
||||
room_id_to_thread_id = {}
|
||||
rooms_by_id = {}
|
||||
for room in rooms
|
||||
room_id_to_thread_id[room._id.toString()] = room.thread_id.toString()
|
||||
|
||||
rooms_by_id[room._id.toString()] = room
|
||||
|
||||
threads = {}
|
||||
getThread = (room) ->
|
||||
thread_id = room.thread_id.toString()
|
||||
if threads[thread_id]?
|
||||
return threads[thread_id]
|
||||
else
|
||||
thread = { messages: [] }
|
||||
if room.resolved?
|
||||
thread.resolved = true
|
||||
thread.resolved_at = room.resolved.ts
|
||||
thread.resolved_by_user = UserFormatter.formatUserForClientSide(room.resolved.user)
|
||||
threads[thread_id] = thread
|
||||
return thread
|
||||
|
||||
for message in messages
|
||||
thread_id = room_id_to_thread_id[message.room_id.toString()]
|
||||
threads[thread_id] ?= []
|
||||
threads[thread_id].push MessageFormatter.formatMessageForClientSide(message)
|
||||
room = rooms_by_id[message.room_id.toString()]
|
||||
if room?
|
||||
thread = getThread(room)
|
||||
thread.messages.push MessageFormatter.formatMessageForClientSide(message)
|
||||
|
||||
for thread_id, messages of threads
|
||||
messages.sort (a,b) -> a.timestamp - b.timestamp
|
||||
for thread_id, thread of threads
|
||||
thread.messages.sort (a,b) -> a.timestamp - b.timestamp
|
||||
|
||||
return threads
|
|
@ -25,10 +25,25 @@ module.exports = MessageHttpController =
|
|||
room_ids = rooms.map (r) -> r._id
|
||||
MessageManager.findAllMessagesInRooms room_ids, (error, messages) ->
|
||||
return next(error) if error?
|
||||
MessageManager.populateMessagesWithUsers messages, (error, messages) ->
|
||||
MessageManager.populateMessagesAndRoomsWithUsers messages, rooms, (error) ->
|
||||
return next(error) if error?
|
||||
threads = MessageFormatter.groupMessagesByThreads rooms, messages
|
||||
res.json threads
|
||||
|
||||
resolveThread: (req, res, next) ->
|
||||
{project_id, thread_id} = req.params
|
||||
{user_id} = req.body
|
||||
logger.log {user_id, project_id, thread_id}, "marking thread as resolved"
|
||||
ThreadManager.resolveThread project_id, thread_id, user_id, (error) ->
|
||||
return next(error) if error?
|
||||
res.send 204 # No content
|
||||
|
||||
reopenThread: (req, res, next) ->
|
||||
{project_id, thread_id} = req.params
|
||||
logger.log {project_id, thread_id}, "reopening thread"
|
||||
ThreadManager.reopenThread project_id, thread_id, (error) ->
|
||||
return next(error) if error?
|
||||
res.send 204 # No content
|
||||
|
||||
_sendMessage: (client_thread_id, req, res, next) ->
|
||||
{user_id, content} = req?.body
|
||||
|
@ -40,9 +55,9 @@ module.exports = MessageHttpController =
|
|||
return next(error) if error?
|
||||
MessageManager.createMessage thread._id, user_id, content, Date.now(), (error, message) ->
|
||||
return next(error) if error?
|
||||
MessageManager.populateMessagesWithUsers [message], (error, messages) ->
|
||||
MessageManager.populateMessagesAndRoomsWithUsers [message], [], (error) ->
|
||||
return next(error) if error?
|
||||
message = MessageFormatter.formatMessageForClientSide(messages[0])
|
||||
message = MessageFormatter.formatMessageForClientSide(message)
|
||||
message.room =
|
||||
id: project_id
|
||||
res.send(201, message)
|
||||
|
@ -64,7 +79,7 @@ module.exports = MessageHttpController =
|
|||
logger.log {limit, before, project_id, client_thread_id, thread_object_id}, "found or created thread"
|
||||
MessageManager.getMessages thread_object_id, limit, before, (error, messages) ->
|
||||
return next(error) if error?
|
||||
MessageManager.populateMessagesWithUsers messages, (error, messages) ->
|
||||
MessageManager.populateMessagesAndRoomsWithUsers messages, [], (error) ->
|
||||
return next(error) if error?
|
||||
messages = MessageFormatter.formatMessagesForClientSide messages
|
||||
logger.log {project_id, messages}, "got messages"
|
||||
|
|
|
@ -28,7 +28,7 @@ module.exports = MessageManager =
|
|||
room_id: { $in: room_ids }
|
||||
}, callback
|
||||
|
||||
populateMessagesWithUsers: (messages, callback = (error, messages) ->) ->
|
||||
populateMessagesAndRoomsWithUsers: (messages, rooms, callback = (error) ->) ->
|
||||
jobs = new Array()
|
||||
|
||||
userCache = {}
|
||||
|
@ -48,7 +48,18 @@ module.exports = MessageManager =
|
|||
return callback(error) if error?
|
||||
delete message.user_id
|
||||
message.user = user
|
||||
callback(null, message)
|
||||
callback()
|
||||
|
||||
for room in rooms
|
||||
do (room) ->
|
||||
if !room?.resolved?.user_id?
|
||||
return
|
||||
jobs.push (callback) ->
|
||||
getUserDetails room.resolved.user_id.toString(), (error, user) ->
|
||||
return callback(error) if error?
|
||||
delete room.resolved.user_id
|
||||
room.resolved.user = user
|
||||
callback()
|
||||
|
||||
async.series jobs, callback
|
||||
|
||||
|
|
|
@ -27,8 +27,29 @@ module.exports = ThreadManager =
|
|||
project_id: ObjectId(project_id.toString())
|
||||
thread_id: { $exists: true }
|
||||
}, {
|
||||
thread_id: 1
|
||||
thread_id: 1,
|
||||
resolved: 1
|
||||
}, callback
|
||||
|
||||
resolveThread: (project_id, thread_id, user_id, callback = (error) ->) ->
|
||||
db.rooms.update {
|
||||
project_id: ObjectId(project_id.toString())
|
||||
thread_id: ObjectId(thread_id.toString())
|
||||
}, {
|
||||
$set: {
|
||||
resolved: {
|
||||
user_id: user_id
|
||||
ts: new Date()
|
||||
}
|
||||
}
|
||||
}, callback
|
||||
|
||||
|
||||
reopenThread: (project_id, thread_id, callback = (error) ->) ->
|
||||
db.rooms.update {
|
||||
project_id: ObjectId(project_id.toString())
|
||||
thread_id: ObjectId(thread_id.toString())
|
||||
}, {
|
||||
$unset: {
|
||||
resolved: true
|
||||
}
|
||||
}, callback
|
||||
|
|
|
@ -24,15 +24,14 @@ module.exports = Router =
|
|||
|
||||
app.post "/project/:project_id/thread/:thread_id/messages", MessageHttpController.sendThreadMessage
|
||||
app.get "/project/:project_id/threads", MessageHttpController.getAllThreads
|
||||
# app.get "/project/:project_id/thread", MessageHttpController.getAllThreadMessages
|
||||
#
|
||||
|
||||
# app.post "/project/:project_id/thread/:thread_id/messages/:message_id/edit", MessageHttpController.editMessage
|
||||
# app.del "/project/:project_id/thread/:thread_id/messages/:message_id", MessageHttpController.deleteMessage
|
||||
#
|
||||
# app.post "/project/:project_id/thread/:thread_id/resolve", MessageHttpController.resolveThread
|
||||
# app.post "/project/:project_id/thread/:thread_id/reopen", MessageHttpController.reopenThread
|
||||
|
||||
app.post "/project/:project_id/thread/:thread_id/resolve", MessageHttpController.resolveThread
|
||||
app.post "/project/:project_id/thread/:thread_id/reopen", MessageHttpController.reopenThread
|
||||
# app.del "/project/:project_id/thread/:thread_id", MessageHttpController.deleteThread
|
||||
#
|
||||
|
||||
app.get "/status", (req, res, next) ->
|
||||
res.send("chat is alive")
|
||||
|
||||
|
|
|
@ -71,20 +71,20 @@ describe "Getting messages", ->
|
|||
ChatClient.getThreads @project_id, (error, response, threads) =>
|
||||
expect(Object.keys(threads).length).to.equal 2
|
||||
thread1 = threads[@thread_id1]
|
||||
expect(thread1.length).to.equal 2
|
||||
expect(thread1.messages.length).to.equal 2
|
||||
thread2 = threads[@thread_id2]
|
||||
expect(thread2.length).to.equal 2
|
||||
expect(thread2.messages.length).to.equal 2
|
||||
|
||||
expect(thread1[0].content).to.equal "one"
|
||||
expect(thread1[0].user).to.deep.equal {
|
||||
expect(thread1.messages[0].content).to.equal "one"
|
||||
expect(thread1.messages[0].user).to.deep.equal {
|
||||
id: @user_id1
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
email: "jane@example.com"
|
||||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("jane@example.com").digest("hex")}"
|
||||
}
|
||||
expect(thread1[1].content).to.equal "three"
|
||||
expect(thread1[1].user).to.deep.equal {
|
||||
expect(thread1.messages[1].content).to.equal "three"
|
||||
expect(thread1.messages[1].user).to.deep.equal {
|
||||
id: @user_id1
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
|
@ -92,16 +92,16 @@ describe "Getting messages", ->
|
|||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("jane@example.com").digest("hex")}"
|
||||
}
|
||||
|
||||
expect(thread2[0].content).to.equal "two"
|
||||
expect(thread2[0].user).to.deep.equal {
|
||||
expect(thread2.messages[0].content).to.equal "two"
|
||||
expect(thread2.messages[0].user).to.deep.equal {
|
||||
id: @user_id2
|
||||
first_name: "John"
|
||||
last_name: "Doe"
|
||||
email: "john@example.com"
|
||||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("john@example.com").digest("hex")}"
|
||||
}
|
||||
expect(thread2[1].content).to.equal "four"
|
||||
expect(thread2[1].user).to.deep.equal {
|
||||
expect(thread2.messages[1].content).to.equal "four"
|
||||
expect(thread2.messages[1].user).to.deep.equal {
|
||||
id: @user_id2
|
||||
first_name: "John"
|
||||
last_name: "Doe"
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
{ObjectId} = require "../../../app/js/mongojs"
|
||||
expect = require("chai").expect
|
||||
crypto = require "crypto"
|
||||
|
||||
MockWebApi = require "./helpers/MockWebApi"
|
||||
ChatClient = require "./helpers/ChatClient"
|
||||
|
||||
describe "Resolving a thread", ->
|
||||
before ->
|
||||
@project_id = ObjectId().toString()
|
||||
@user_id = ObjectId().toString()
|
||||
MockWebApi.addUser @user_id, @user = {
|
||||
id: @user_id
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
email: "jane@example.com"
|
||||
}
|
||||
|
||||
describe "with a resolved thread", ->
|
||||
before (done) ->
|
||||
@thread_id = ObjectId().toString()
|
||||
@content = "resolved message"
|
||||
ChatClient.sendMessage @project_id, @thread_id, @user_id, @content, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 201
|
||||
ChatClient.resolveThread @project_id, @thread_id, @user_id, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 204
|
||||
done()
|
||||
|
||||
it "should then list the thread as resolved", (done) ->
|
||||
ChatClient.getThreads @project_id, (error, response, threads) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 200
|
||||
expect(threads[@thread_id].resolved).to.equal true
|
||||
expect(threads[@thread_id].resolved_by_user).to.deep.equal {
|
||||
id: @user_id
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
email: "jane@example.com"
|
||||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("jane@example.com").digest("hex")}"
|
||||
}
|
||||
resolved_at = new Date(threads[@thread_id].resolved_at)
|
||||
expect(new Date() - resolved_at).to.be.below 1000
|
||||
done()
|
||||
|
||||
describe "when a thread is not resolved", ->
|
||||
before (done) ->
|
||||
@thread_id = ObjectId().toString()
|
||||
@content = "open message"
|
||||
ChatClient.sendMessage @project_id, @thread_id, @user_id, @content, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 201
|
||||
done()
|
||||
|
||||
it "should not list the thread as resolved", (done) ->
|
||||
ChatClient.getThreads @project_id, (error, response, threads) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 200
|
||||
expect(threads[@thread_id].resolved).to.be.undefined
|
||||
done()
|
||||
|
||||
describe "when a thread is resolved then reopened", ->
|
||||
before (done) ->
|
||||
@thread_id = ObjectId().toString()
|
||||
@content = "resolved message"
|
||||
ChatClient.sendMessage @project_id, @thread_id, @user_id, @content, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 201
|
||||
ChatClient.resolveThread @project_id, @thread_id, @user_id, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 204
|
||||
ChatClient.reopenThread @project_id, @thread_id, (error, response, body) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 204
|
||||
done()
|
||||
|
||||
it "should not list the thread as resolved", (done) ->
|
||||
ChatClient.getThreads @project_id, (error, response, threads) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 200
|
||||
expect(threads[@thread_id].resolved).to.be.undefined
|
||||
done()
|
|
@ -50,8 +50,8 @@ describe "Sending a message", ->
|
|||
ChatClient.getThreads @project_id, (error, response, threads) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 200
|
||||
expect(threads[@thread_id].length).to.equal 1
|
||||
expect(threads[@thread_id][0].content).to.equal @content
|
||||
expect(threads[@thread_id].messages.length).to.equal 1
|
||||
expect(threads[@thread_id].messages[0].content).to.equal @content
|
||||
done()
|
||||
|
||||
describe "with a malformed user_id", ->
|
||||
|
|
|
@ -27,4 +27,17 @@ module.exports =
|
|||
request.get {
|
||||
url: "/project/#{project_id}/threads",
|
||||
json: true
|
||||
}, callback
|
||||
|
||||
resolveThread: (project_id, thread_id, user_id, callback) ->
|
||||
request.post {
|
||||
url: "/project/#{project_id}/thread/#{thread_id}/resolve",
|
||||
json: {
|
||||
user_id: user_id
|
||||
}
|
||||
}, callback
|
||||
|
||||
reopenThread: (project_id, thread_id, callback) ->
|
||||
request.post {
|
||||
url: "/project/#{project_id}/thread/#{thread_id}/reopen",
|
||||
}, callback
|
Loading…
Reference in a new issue