diff --git a/services/chat/Gruntfile.coffee b/services/chat/Gruntfile.coffee index 3496569094..b4d7b91f34 100644 --- a/services/chat/Gruntfile.coffee +++ b/services/chat/Gruntfile.coffee @@ -12,14 +12,6 @@ module.exports = (grunt) -> src: "app.js" coffee: - client: - expand: true, - flatten: false, - cwd: 'public/coffee', - src: ['**/*.coffee'], - dest: 'public/build/', - ext: '.js' - server: expand: true, flatten: false, @@ -56,47 +48,7 @@ module.exports = (grunt) -> files: ['app/**/*.coffee', 'test/unit/**/*.coffee'] tasks: ['compile:server', 'compile:unit_tests', 'mochaTest'] - client_coffee: - files: ['public/**/*.coffee'] - tasks: ['compile'] - - less: - files: ['public/less/*.less'] - tasks: ['compile'] - - jade: - files: ['public/jade/*.jade'] - tasks: ['compile'] - - - less: - production: - files: - "public/build/css/chat.css": "public/less/chat.less" - - jade: - compile: - files: - "public/build/html/templates.html": ["public/jade/templates.jade"] - - requirejs: - compile: - options: - mainConfigFile: 'public/app.build.js', - - uglify: - my_target: - files: - 'public/build/chat.js': ['public/build/chat.js'] - - copy: - main: - expand: true - cwd: 'public/js' - src: '**' - dest: 'public/build/' - - clean: ["public/build", "app/js", "test/unit/js"] + clean: ["app/js", "test/unit/js"] nodemon: dev: @@ -127,11 +79,6 @@ module.exports = (grunt) -> grunt.loadNpmTasks 'grunt-contrib-coffee' grunt.loadNpmTasks 'grunt-contrib-watch' - grunt.loadNpmTasks 'grunt-contrib-copy' - grunt.loadNpmTasks 'grunt-contrib-less' - grunt.loadNpmTasks 'grunt-contrib-jade' - grunt.loadNpmTasks 'grunt-contrib-requirejs' - grunt.loadNpmTasks 'grunt-contrib-uglify' grunt.loadNpmTasks 'grunt-nodemon' grunt.loadNpmTasks 'grunt-contrib-clean' grunt.loadNpmTasks 'grunt-concurrent' @@ -142,10 +89,9 @@ module.exports = (grunt) -> grunt.loadNpmTasks 'grunt-forever' - grunt.registerTask 'compile', ['clean', 'copy', 'coffee', 'less', 'jade', 'requirejs'] + grunt.registerTask 'compile', ['clean', 'coffee'] grunt.registerTask 'install', ['compile'] grunt.registerTask 'default', ['compile', 'bunyan', 'execute'] - grunt.registerTask 'compileAndCompress', ['compile', 'uglify'] grunt.registerTask 'test:unit', ['compile', 'mochaTest:unit'] grunt.registerTask 'test:acceptance', ['compile:acceptance_tests', 'mochaTest:acceptance'] diff --git a/services/chat/app/coffee/Features/Messages/MessageFormatter.coffee b/services/chat/app/coffee/Features/Messages/MessageFormatter.coffee index 3d77cda1dd..012f1f8882 100644 --- a/services/chat/app/coffee/Features/Messages/MessageFormatter.coffee +++ b/services/chat/app/coffee/Features/Messages/MessageFormatter.coffee @@ -1,5 +1,3 @@ -UserFormatter = require "../Users/UserFormatter" - module.exports = MessageFormatter = formatMessageForClientSide: (message) -> if message._id? @@ -9,8 +7,38 @@ module.exports = MessageFormatter = id: message.id content: message.content timestamp: message.timestamp - user: UserFormatter.formatUserForClientSide(message.user) + user_id: message.user_id return formattedMessage formatMessagesForClientSide: (messages) -> (@formatMessageForClientSide(message) for message in messages) + + groupMessagesByThreads: (rooms, messages) -> + rooms_by_id = {} + for room in rooms + 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_id = room.resolved.user_id + threads[thread_id] = thread + return thread + + for message in messages + room = rooms_by_id[message.room_id.toString()] + if room? + thread = getThread(room) + thread.messages.push MessageFormatter.formatMessageForClientSide(message) + + for thread_id, thread of threads + thread.messages.sort (a,b) -> a.timestamp - b.timestamp + + return threads \ No newline at end of file diff --git a/services/chat/app/coffee/Features/Messages/MessageHttpController.coffee b/services/chat/app/coffee/Features/Messages/MessageHttpController.coffee index c3f28fe86d..d36206afe9 100644 --- a/services/chat/app/coffee/Features/Messages/MessageHttpController.coffee +++ b/services/chat/app/coffee/Features/Messages/MessageHttpController.coffee @@ -2,61 +2,78 @@ logger = require "logger-sharelatex" metrics = require "metrics-sharelatex" MessageManager = require "./MessageManager" MessageFormatter = require "./MessageFormatter" -RoomManager = require "../Rooms/RoomManager" +ThreadManager = require "../Threads/ThreadManager" +{ObjectId} = require "../../mongojs" module.exports = MessageHttpController = DEFAULT_MESSAGE_LIMIT: 50 + + getGlobalMessages: (req, res, next) -> + MessageHttpController._getMessages(ThreadManager.GLOBAL_THREAD, req, res, next) - sendMessage: (req, res, next) -> + sendGlobalMessage: (req, res, next) -> + MessageHttpController._sendMessage(ThreadManager.GLOBAL_THREAD, req, res, next) + + sendThreadMessage: (req, res, next) -> + MessageHttpController._sendMessage(req.params.thread_id, req, res, next) + + getAllThreads: (req, res, next) -> + {project_id} = req.params + logger.log {project_id}, "getting all threads" + ThreadManager.findAllThreadRooms project_id, (error, rooms) -> + return next(error) if error? + room_ids = rooms.map (r) -> r._id + MessageManager.findAllMessagesInRooms room_ids, (error, messages) -> + 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 {project_id} = req.params - - logger.log user_id: user_id, content: content, "new message recived" - RoomManager.findOrCreateRoom project_id: project_id, (error, room) -> + if !ObjectId.isValid(user_id) + return res.send(400, "Invalid user_id") + logger.log {client_thread_id, project_id, user_id, content}, "new message received" + ThreadManager.findOrCreateThread project_id, client_thread_id, (error, thread) -> return next(error) if error? - newMessageOpts = - content: content - room_id: room._id - user_id: user_id - timestamp: Date.now() - MessageManager.createMessage newMessageOpts, (error, message) -> - if err? - logger.err err:error, user_id:user_id, "something went wrong with create message" - return next(err) - MessageManager.populateMessagesWithUsers [message], (error, messages) -> - if error? - logger.err err:error, user_id:user_id, "something went wrong populateMessagesWithUsers" - return next("something went wrong") - message = MessageFormatter.formatMessageForClientSide(messages[0]) - message.room = - id: project_id - res.send(201, message) + MessageManager.createMessage thread._id, user_id, content, Date.now(), (error, message) -> + return next(error) if error? + message = MessageFormatter.formatMessageForClientSide(message) + message.room_id = project_id + res.send(201, message) - getMessages: (req, res, next) -> + _getMessages: (client_thread_id, req, res, next) -> {project_id} = req.params - query = {} if req.query?.before? - query.timestamp = $lt: parseInt(req.query.before, 10) + before = parseInt(req.query.before, 10) + else + before = null if req.query?.limit? limit = parseInt(req.query.limit, 10) else limit = MessageHttpController.DEFAULT_MESSAGE_LIMIT - options = - order_by: "timestamp" - sort_order: -1 - limit: limit - logger.log options:options, "get message request recived" - RoomManager.findOrCreateRoom project_id: project_id, (error, room) -> + logger.log {limit, before, project_id, client_thread_id}, "get message request received" + ThreadManager.findOrCreateThread project_id, client_thread_id, (error, thread) -> return next(error) if error? - query.room_id = room._id - MessageManager.getMessages query, options, (error, messages) -> - if error? - logger.err err:error, "something went getMessages" - return next("something went wrong") - MessageManager.populateMessagesWithUsers messages, (error, messages) -> - if error? - logger.err err:error, "something went populateMessagesWithUsers" - return next("something went wrong") - messages = MessageFormatter.formatMessagesForClientSide messages - logger.log project_id: project_id, "got messages" - res.send 200, messages \ No newline at end of file + thread_object_id = thread._id + 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? + messages = MessageFormatter.formatMessagesForClientSide messages + logger.log {project_id, messages}, "got messages" + res.send 200, messages diff --git a/services/chat/app/coffee/Features/Messages/MessageManager.coffee b/services/chat/app/coffee/Features/Messages/MessageManager.coffee index a66f465163..317721ea28 100644 --- a/services/chat/app/coffee/Features/Messages/MessageManager.coffee +++ b/services/chat/app/coffee/Features/Messages/MessageManager.coffee @@ -1,50 +1,32 @@ mongojs = require "../../mongojs" db = mongojs.db ObjectId = mongojs.ObjectId -WebApiManager = require "../WebApi/WebApiManager" async = require "async" module.exports = MessageManager = - createMessage: (message, callback = (error, message) ->) -> - message = @_ensureIdsAreObjectIds(message) - db.messages.save message, callback + createMessage: (room_id, user_id, content, timestamp, callback = (error, message) ->) -> + newMessageOpts = + content: content + room_id: room_id + user_id: user_id + timestamp: timestamp + newMessageOpts = @_ensureIdsAreObjectIds(newMessageOpts) + db.messages.save newMessageOpts, callback - getMessages: (query, options, callback = (error, messages) ->) -> + getMessages: (room_id, limit, before, callback = (error, messages) ->) -> + query = + room_id: room_id + if before? + query.timestamp = { $lt: before } query = @_ensureIdsAreObjectIds(query) - cursor = db.messages.find(query) - if options.order_by? - options.sort_order ||= 1 - sortQuery = {} - sortQuery[options.order_by] = options.sort_order - cursor = cursor.sort(sortQuery) - if options.limit? - cursor = cursor.limit(options.limit) + cursor = db.messages.find(query).sort({ timestamp: -1 }).limit(limit) cursor.toArray callback - - populateMessagesWithUsers: (messages, callback = (error, messages) ->) -> - jobs = new Array() - - userCache = {} - getUserDetails = (user_id, callback = (error, user) ->) -> - return callback(null, userCache[user_id]) if userCache[user_id]? - WebApiManager.getUserDetails user_id, (error, user) -> - return callback(error) if error? - userCache[user_id] = user - callback null, user - - for message in messages - do (message) -> - if !message? - return - jobs.push (callback) -> - getUserDetails message.user_id.toString(), (error, user) -> - return callback(error) if error? - delete message.user_id - message.user = user - callback(null, message) - - async.series jobs, callback + findAllMessagesInRooms: (room_ids, callback = (error, messages) ->) -> + db.messages.find { + room_id: { $in: room_ids } + }, callback + _ensureIdsAreObjectIds: (query) -> if query.user_id? and query.user_id not instanceof ObjectId query.user_id = ObjectId(query.user_id) diff --git a/services/chat/app/coffee/Features/Rooms/RoomManager.coffee b/services/chat/app/coffee/Features/Rooms/RoomManager.coffee deleted file mode 100644 index c9820467e8..0000000000 --- a/services/chat/app/coffee/Features/Rooms/RoomManager.coffee +++ /dev/null @@ -1,18 +0,0 @@ -mongojs = require("../../mongojs") -db = mongojs.db -ObjectId = mongojs.ObjectId - -module.exports = RoomManager = - findOrCreateRoom: (query, callback = (error, room) ->) -> - if query.project_id? and query.project_id not instanceof ObjectId - query.project_id = ObjectId(query.project_id) - - db.rooms.findOne query, (error, room) -> - return callback(error) if error? - if room? - callback null, room - else - db.rooms.save query, (error, room) -> - return callback(error) if error? - callback null, room - diff --git a/services/chat/app/coffee/Features/Threads/ThreadManager.coffee b/services/chat/app/coffee/Features/Threads/ThreadManager.coffee new file mode 100644 index 0000000000..8adee1591e --- /dev/null +++ b/services/chat/app/coffee/Features/Threads/ThreadManager.coffee @@ -0,0 +1,55 @@ +mongojs = require("../../mongojs") +db = mongojs.db +ObjectId = mongojs.ObjectId + +module.exports = ThreadManager = + GLOBAL_THREAD: "GLOBAL" + + findOrCreateThread: (project_id, thread_id, callback = (error, thread) ->) -> + query = + project_id: ObjectId(project_id.toString()) + + if thread_id? and thread_id != ThreadManager.GLOBAL_THREAD + query.thread_id = ObjectId(thread_id.toString()) + + # Threads used to be called rooms, and still are in the DB + db.rooms.findOne query, (error, thread) -> + return callback(error) if error? + if thread? + callback null, thread + else + db.rooms.save query, (error, thread) -> + return callback(error) if error? + callback null, thread + + findAllThreadRooms: (project_id, callback = (error, rooms) ->) -> + db.rooms.find { + project_id: ObjectId(project_id.toString()) + thread_id: { $exists: true } + }, { + 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 diff --git a/services/chat/app/coffee/Features/Users/UserFormatter.coffee b/services/chat/app/coffee/Features/Users/UserFormatter.coffee deleted file mode 100644 index 87af9b8d5d..0000000000 --- a/services/chat/app/coffee/Features/Users/UserFormatter.coffee +++ /dev/null @@ -1,19 +0,0 @@ -crypto = require "crypto" - -module.exports = UserFormatter = - formatUserForClientSide: (user) -> - return null if !user? - if user._id? - user.id = user._id.toString() - delete user._id - return { - id: user.id - first_name: user.first_name - last_name: user.last_name - email: user.email - gravatar_url: @_getGravatarUrlForEmail(user.email) - } - - _getGravatarUrlForEmail: (email) -> - hash = crypto.createHash("md5").update(email.toLowerCase()).digest("hex") - return "//www.gravatar.com/avatar/#{hash}" diff --git a/services/chat/app/coffee/Features/WebApi/WebApiManager.coffee b/services/chat/app/coffee/Features/WebApi/WebApiManager.coffee deleted file mode 100644 index 9f3960d612..0000000000 --- a/services/chat/app/coffee/Features/WebApi/WebApiManager.coffee +++ /dev/null @@ -1,43 +0,0 @@ -request = require('request').defaults(jar: false) -Settings = require("settings-sharelatex") - -# DEPRECATED! This method of getting user details via chat is deprecated -# in the way we lay out our services. -# Instead, web should be responsible for collecting the raw data (user_ids) and -# filling it out with calls to other services. All API calls should create a -# tree-like structure as much as possible, with web as the root. -module.exports = WebApiManager = - apiRequest: (url, method, options = {}, callback = (error, result) ->) -> - if typeof options == "function" - callback = options - options = {} - url = "#{Settings.apis.web.url}#{url}" - options.url = url - options.method = method - request options, (error, response, body) -> - return callback(error) if error? - if 200 <= response.statusCode < 300 - try - result = JSON.parse(body) - catch e - return callback(e) - return callback null, result - else - error = new Error("web api returned non-success code: #{response.statusCode}") - error.statusCode = response.statusCode - return callback error - - getUserDetails: (user_id, callback = (error, details) ->) -> - @apiRequest "/user/#{user_id}/personal_info", "get", { - auth: - user: Settings.apis.web.user - pass: Settings.apis.web.pass - sendImmediately: true - }, (error, data) -> - if error? - if error.statusCode == 404 - return callback null, null - else - return callback error - else - return callback null, data diff --git a/services/chat/app/coffee/mongojs.coffee b/services/chat/app/coffee/mongojs.coffee index 134fcd05ae..44b54c15f4 100644 --- a/services/chat/app/coffee/mongojs.coffee +++ b/services/chat/app/coffee/mongojs.coffee @@ -1,6 +1,6 @@ Settings = require("settings-sharelatex") mongojs = require "mongojs" -db = mongojs.connect(Settings.mongo.url, ["rooms", "messages"]) +db = mongojs(Settings.mongo.url, ["rooms", "messages"]) module.exports = db: db ObjectId: mongojs.ObjectId diff --git a/services/chat/app/coffee/router.coffee b/services/chat/app/coffee/router.coffee index 7e19ec62c5..88179b7f3a 100644 --- a/services/chat/app/coffee/router.coffee +++ b/services/chat/app/coffee/router.coffee @@ -1,10 +1,37 @@ MessageHttpController = require('./Features/Messages/MessageHttpController') +{ObjectId} = require "./mongojs" module.exports = Router = route: (app) -> - app.get "/room/:project_id/messages", MessageHttpController.getMessages - app.post "/room/:project_id/messages", MessageHttpController.sendMessage - + app.param 'project_id', (req, res, next, project_id) -> + if ObjectId.isValid(project_id) + next() + else + res.send 400, "Invalid project_id" + + app.param 'thread_id', (req, res, next, thread_id) -> + if ObjectId.isValid(thread_id) + next() + else + res.send 400, "Invalid thread_id" + + # These are for backwards compatibility + app.get "/room/:project_id/messages", MessageHttpController.getGlobalMessages + app.post "/room/:project_id/messages", MessageHttpController.sendGlobalMessage + + app.get "/project/:project_id/messages", MessageHttpController.getGlobalMessages + app.post "/project/:project_id/messages", MessageHttpController.sendGlobalMessage + + app.post "/project/:project_id/thread/:thread_id/messages", MessageHttpController.sendThreadMessage + app.get "/project/:project_id/threads", MessageHttpController.getAllThreads + + # 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.del "/project/:project_id/thread/:thread_id", MessageHttpController.deleteThread + app.get "/status", (req, res, next) -> res.send("chat is alive") diff --git a/services/chat/package.json b/services/chat/package.json index 2f3b2625a3..d30b905039 100644 --- a/services/chat/package.json +++ b/services/chat/package.json @@ -11,8 +11,8 @@ "coffee-script": "~1.7.1", "express": "3.3.1", "logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#master", - "metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.0.0", - "mongojs": "0.18.2", + "metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.6.0", + "mongojs": "^2.4.0", "redis": "~0.10.1", "request": "^2.79.0", "settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0" @@ -25,11 +25,6 @@ "grunt-concurrent": "~0.4.2", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-coffee": "~0.7.0", - "grunt-contrib-copy": "~0.4.1", - "grunt-contrib-jade": "~0.8.0", - "grunt-contrib-less": "~0.8.2", - "grunt-contrib-requirejs": "~0.4.1", - "grunt-contrib-uglify": "~0.2.7", "grunt-contrib-watch": "~0.5.3", "grunt-execute": "^0.2.2", "grunt-forever": "^0.4.7", @@ -37,7 +32,6 @@ "grunt-nodemon": "~0.1.2", "grunt-notify": "~0.2.16", "grunt-plato": "~0.2.1", - "grunt-requirejs": "~0.4.0", "sandboxed-module": "", "sinon": "", "timekeeper": "" diff --git a/services/chat/public/app.build.js b/services/chat/public/app.build.js deleted file mode 100644 index 1614b5cb7b..0000000000 --- a/services/chat/public/app.build.js +++ /dev/null @@ -1,25 +0,0 @@ -requirejs.config({ - baseUrl: "./build", - out: "./build/chat.js", - inlineText:true, - preserveLicenseComments:false, - shim: { - "libs/underscore": { - init: function() { - return _.noConflict(); - } - }, - "libs/backbone": { - deps: ["libs/underscore"], - init: function() { - return Backbone.noConflict(); - } - } - }, - paths: { - "moment": "libs/moment", - }, - name:"chat", - optimize: 'none', - skipDirOptimize: true -}) \ No newline at end of file diff --git a/services/chat/public/coffee/chat.coffee b/services/chat/public/coffee/chat.coffee deleted file mode 100644 index 473c916f83..0000000000 --- a/services/chat/public/coffee/chat.coffee +++ /dev/null @@ -1,109 +0,0 @@ -define [ - "utils/staticLoader" - "libs/underscore" - "libs/backbone" - "libs/jquery.storage" - "models/room" - "models/user" - "views/chatWindowView" - -], (staticLoader, _, Backbone, jqueryStorage, Room, User, ChatWindowView) -> - - staticLoader.appendAssets() - _.templateSettings = escape : /\{\{(.+?)\}\}/g - - class GlobalNotificationManager - constructor: (@chat) -> - @focussed = true - $(window).on "focus", () => - @clearNewMessageNotification() - @focussed = true - $(window).on "blur", () => @focussed = false - - @chat.on "joinedRoom", (room) => - notifyIfAppropriate = (message) => - if message.get("user") != @chat.user and !message.get("preloaded") - @notifyAboutNewMessage() - - room.get("messages").on "add", notifyIfAppropriate - room.on "disconnect", () -> - room.get("messages").off "add", notifyIfAppropriate - - notifyAboutNewMessage: () -> - if !@focussed and !@newMessageNotificationTimeout? - @originalTitle ||= window.document.title - do changeTitle = () => - if window.document.title == @originalTitle - window.document.title = "New Message" - else - window.document.title = @originalTitle - @newMessageNotificationTimeout = setTimeout changeTitle, 800 - - clearNewMessageNotification: () -> - clearTimeout @newMessageNotificationTimeout - delete @newMessageNotificationTimeout - if @originalTitle? - window.document.title = @originalTitle - - class Chat - constructor: (options) -> - _.extend(@, Backbone.Events) - window.chat = @ - @rooms = {} - project_id = window.location.pathname.split( '/' )[2] - @socket = socket = io.connect options.url, { - resource: "chat/socket.io", - "force new connection": true - query:"project_id=#{project_id}" - } - - @socket.on "connect", () => - @connected = true - @getAuthToken (error, auth_token) => - return @handleError(error) if error? - @socket.emit "auth", {auth_token: auth_token}, (error, user_info) => - return @handleError(error) if error? - @user = User.findOrCreate(user_info) - @joinProjectRoom(options.room.project_id) - @trigger "authed" - - @socket.on "disconnect", () => - @connected = false - @trigger "disconnected" - - @socket.on "messageReceived", (data) => - @getRoom(data.message.room.id)?.onMessageReceived(data) - - @socket.on "userJoined", (data) => - @getRoom(data.room.id).addConnectedUser(data.user) - - @socket.on "userLeft", (data) => - @getRoom(data.room.id)?.removeConnectedUser(data.user) - - @globalNotificationManager = new GlobalNotificationManager(@) - - getRoom: (room_id) -> - @rooms[room_id] - - joinProjectRoom: (project_id) -> - if !@room? - @room = new Room( - project_id: project_id - chat: @ - ) - @window = new ChatWindowView({ - room: @room - chat: @ - }) - @room.on "joined", => @trigger("joinedRoom", @room) - - getAuthToken: (callback = (error, auth_token) ->) -> - $.ajax "/user/auth_token", { - success: (data, status, xhr) -> - callback null, data - error: (xhr, status, error) -> - callback error - } - - handleError: (error) -> - console.error error diff --git a/services/chat/public/coffee/collections/connectedUsers.coffee b/services/chat/public/coffee/collections/connectedUsers.coffee deleted file mode 100644 index eee80e014c..0000000000 --- a/services/chat/public/coffee/collections/connectedUsers.coffee +++ /dev/null @@ -1,9 +0,0 @@ -define [ - "libs/backbone" - "models/user" -], (Backbone, User) -> - ConnectedUsers = Backbone.Collection.extend - model: User - - initialize: (models, options) -> - {@chat, @room} = options diff --git a/services/chat/public/coffee/collections/messages.coffee b/services/chat/public/coffee/collections/messages.coffee deleted file mode 100644 index d054df89f2..0000000000 --- a/services/chat/public/coffee/collections/messages.coffee +++ /dev/null @@ -1,45 +0,0 @@ -define [ - "libs/backbone" - "models/message" - "models/user" - -], (Backbone, Message, User) -> - - Messages = Backbone.Collection.extend - model: Message - - initialize: (models, options) -> - {@chat, @room} = options - - fetchMoreMessages: (options = { preloading: false }, callback = (error) ->) -> - limit = Messages.DEFAULT_MESSAGE_LIMIT - - @room.fetchMessages @_buildMessagesQuery(limit), (error, messages) => - if error? - callback(error) - return @chat.handleError(error) - if messages.length < limit - @trigger "noMoreMessages" - @_parseAndAddMessages(messages, options) - callback() - - _parseAndAddMessages: (messages, options) -> - for message in messages - user = User.findOrCreate message.user - @add new Message( - content : message.content - timestamp : message.timestamp - user : user - preloaded : !!options.preloading - ), at: 0 - - _buildMessagesQuery: (limit) -> - query = - limit: limit - firstMessage = @at(0) - if firstMessage? - query.before = firstMessage.get("timestamp") - return query - Messages.DEFAULT_MESSAGE_LIMIT = 50 - - return Messages \ No newline at end of file diff --git a/services/chat/public/coffee/models/message.coffee b/services/chat/public/coffee/models/message.coffee deleted file mode 100644 index 5b83fe686a..0000000000 --- a/services/chat/public/coffee/models/message.coffee +++ /dev/null @@ -1,5 +0,0 @@ -define [ - "libs/backbone" -], (Backbone) -> - - Message = Backbone.Model.extend {} \ No newline at end of file diff --git a/services/chat/public/coffee/models/room.coffee b/services/chat/public/coffee/models/room.coffee deleted file mode 100644 index df51bb57e1..0000000000 --- a/services/chat/public/coffee/models/room.coffee +++ /dev/null @@ -1,85 +0,0 @@ -define [ - "libs/underscore" - "libs/backbone" - "collections/messages" - "collections/connectedUsers" - "models/user" - "models/message" -], (_, Backbone, Messages, ConnectedUsers, User, Message) -> - - - Room = Backbone.Model.extend - initialize: () -> - @chat = @get("chat") - @set "messages", new Messages([], chat: @chat, room: @) - @set "connectedUsers", new ConnectedUsers([], chat: @chat, room: @) - - @get("connectedUsers").on "change", () -> - @get("connectedUsers").on "add", () -> - @get("connectedUsers").on "remove", () -> - - @connected = false - - @chat.on "authed", () => @join() - @chat.on "disconnected", () => @_onDisconnect() - - join: () -> - @chat.socket.emit "joinRoom", room: project_id: @get("project_id"), (error, data) => - return @chat.handleError(error) if error? - room = data.room - @set("id", room.id) - @chat.rooms[room.id] = @ - @addConnectedUsers(room.connectedUsers) - @_onJoin() - - _onJoin: () -> - @trigger "joined" - @connected = true - - if @get("messages").models.length == 0 - @get("messages").fetchMoreMessages preloading: true, () => - @trigger("afterMessagesPreloaded") - - _onDisconnect: () -> - @trigger "disconnected" - @connected = false - - addConnectedUsers: (users) -> - for user in users - @addConnectedUser(user) - - addConnectedUser: (user) -> - if user not instanceof User - user = User.findOrCreate(user) - @get("connectedUsers").add user - - removeConnectedUser: (user) -> - if user not instanceof User - user = User.findOrCreate(user) - @get("connectedUsers").remove user - - sendMessage: (content, callback = (error) ->) -> - if !@connected - return callback(new Error("Not connected")) - @chat.socket.emit "sendMessage", { - message: - content: content - room: - id: @get("id") - } - - fetchMessages: (query, callback = (error, messages) ->) -> - if !@connected - return callback(new Error("Not connected")) - query.room = id: @get("id") - @chat.socket.emit "getMessages", query, callback - - onMessageReceived: (data) -> - message = data.message - user = User.findOrCreate message.user - message = new Message( - content : data.message.content - timestamp : data.message.timestamp - user : user - ) - @get("messages").add message \ No newline at end of file diff --git a/services/chat/public/coffee/models/user.coffee b/services/chat/public/coffee/models/user.coffee deleted file mode 100644 index 103e9c9c5f..0000000000 --- a/services/chat/public/coffee/models/user.coffee +++ /dev/null @@ -1,13 +0,0 @@ -define [ - "libs/backbone" -], (Backbone, room) -> - - User = Backbone.Model.extend {}, - findOrCreate: (attributes) -> - User.cache ||= {} - if User.cache[attributes.id]? - return User.cache[attributes.id] - else - user = new User(attributes) - User.cache[attributes.id] = user - return user \ No newline at end of file diff --git a/services/chat/public/coffee/utils/staticLoader.coffee b/services/chat/public/coffee/utils/staticLoader.coffee deleted file mode 100644 index 763f322087..0000000000 --- a/services/chat/public/coffee/utils/staticLoader.coffee +++ /dev/null @@ -1,10 +0,0 @@ -define [ - "text!html/templates.html" - "text!css/chat.css" -], (templates, css)-> - - appendAssets : -> - $(document.body).append($(templates)) - style = $("