diff --git a/node_modules/c9/git.js b/node_modules/c9/git.js index dea02285..6228914a 100644 --- a/node_modules/c9/git.js +++ b/node_modules/c9/git.js @@ -1,7 +1,5 @@ "use strict"; -require("amd-loader"); - var Fs = require("fs"); var Path = require("path"); var exec = require("child_process").exec; diff --git a/package.json b/package.json index 2d8879fe..69b2e446 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "c9", "description": "New Cloud9 Client", - "version": "3.1.3131", + "version": "3.1.3140", "author": "Ajax.org B.V. ", "private": true, "main": "bin/c9", @@ -71,7 +71,7 @@ "c9.ide.language.javascript.infer": "#b9c2e4bdb8", "c9.ide.language.jsonalyzer": "#a0549e14ff", "c9.ide.language.codeintel": "#0fe92d6f46", - "c9.ide.collab": "#54aa1cbee0", + "c9.ide.collab": "#f60595d380", "c9.ide.local": "#9169fec157", "c9.ide.find": "#e632ecf4be", "c9.ide.find.infiles": "#ad9ff74638", diff --git a/plugins/c9.core/util.js b/plugins/c9.core/util.js index af2f4d63..dc50b101 100644 --- a/plugins/c9.core/util.js +++ b/plugins/c9.core/util.js @@ -196,12 +196,19 @@ define(function(require, exports, module) { return "<" + tag + " " + plugin.toXmlAttributes(attrs) + (noclose ? ">" : " />"); }; + function isMd5String(str) { + return /^[0-9a-f]{32}$/.test(str); + } + /** * Returns the gravatar url for this user * @param {Number} size the size of the image */ plugin.getGravatarUrl = function getGravatarUrl(email, size, defaultImage) { - var md5Email = apf.crypto.MD5.hex_md5((email || "").trim().toLowerCase()); + var md5Email = email + if (!isMd5String(md5Email)) { + md5Email = apf.crypto.MD5.hex_md5((email || "").trim().toLowerCase()); + } return "https://secure.gravatar.com/avatar/" + md5Email + "?s=" + size + "&d=" + (defaultImage || "retro"); }; diff --git a/plugins/c9.core/util_test.js b/plugins/c9.core/util_test.js index ef668547..57b4df7c 100644 --- a/plugins/c9.core/util_test.js +++ b/plugins/c9.core/util_test.js @@ -9,6 +9,7 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) expect.setupArchitectTest([ "plugins/c9.core/ext", "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", // Mock plugins { consumes: [], @@ -32,6 +33,15 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) }); }); + describe("getGravatarUrl", function() { + it("Should hash a normal email", function() { + expect(util.getGravatarUrl("test@test.com", 32)).to.match(/^https:\/\/secure.gravatar.com\/avatar\/b642b4217b34b1e8d3bd915fc65c4452.*/); + }); + it("Should use not re-hash an md5 passed in", function() { + expect(util.getGravatarUrl("b642b4217b34b1e8d3bd915fc65c4452", 32)).to.match(/^https:\/\/secure.gravatar.com\/avatar\/b642b4217b34b1e8d3bd915fc65c4452.*/); + }); + }); + describe('normalizePath', function() { var normalizePath = util.normalizePath; it('should handle home in workspaceDir', function() { diff --git a/plugins/c9.vfs.server/vfs.server.js b/plugins/c9.vfs.server/vfs.server.js index 3be49599..069fd3ed 100644 --- a/plugins/c9.vfs.server/vfs.server.js +++ b/plugins/c9.vfs.server/vfs.server.js @@ -277,7 +277,7 @@ function plugin(options, imports, register) { var vfsid = req.params.vfsid; var scope = req.params.scope; var path = req.params.path; - + var entry = cache.get(vfsid); if (!entry) { var err = new error.PreconditionFailed("VFS connection does not exist"); @@ -335,10 +335,34 @@ function plugin(options, imports, register) { user.save && user.save(function() {}); } } - + + function handlePublish(vfs, messageString) { + var message = JSON.parse(messageString); + switch (message.action) { + case "remove_member": + case "update_member_access": + handleProjectMemberAccessChange(vfs, message); + break; + default: + break; + } + } + + function handleProjectMemberAccessChange(vfs, message) { + if (vfs.uid !== message.body.uid) return; + + console.log("Removing ", vfs.id, " for user ", vfs.uid, " project ", vfs.pid, " from the vfs connection cache"); + + // Remove next tick so client has time to recieve final "You've been removed" PubSub message. + setTimeout(function() { + cache.remove(vfs.id); + }, 100); + } + register(null, { "vfs.server": { - get section() { return section; } + get section() { return section; }, + get handlePublish() { return handlePublish; } } }); } diff --git a/plugins/c9.vfs.server/vfs.server_test.js b/plugins/c9.vfs.server/vfs.server_test.js new file mode 100644 index 00000000..492907e3 --- /dev/null +++ b/plugins/c9.vfs.server/vfs.server_test.js @@ -0,0 +1,122 @@ +#!/usr/bin/env node +"use strict"; +"use server"; + + +require("c9/inline-mocha")(module); +if (typeof define === "undefined") { + require("amd-loader"); +} + +var sinon = require("sinon"); +var assert = require("assert"); +var vfsServer = require("./vfs.server"); +var mockDb = {}; +var mockCache = { + remove: sinon.stub() +}; +var mockApi = { + section: sinon.stub().returns({ + registerType: sinon.stub(), + post: sinon.stub(), + get: sinon.stub(), + delete: sinon.stub(), + all: sinon.stub() + }), + use: sinon.stub(), + ensureAdmin: sinon.stub(), + get: sinon.stub(), + authenticate: sinon.stub() +}; +var mockRender = { + setTemplatePath: sinon.stub() +}; +var mockConnect = { + getModule: sinon.stub().returns({ + compress: sinon.stub() + }) +}; + +describe(__filename, function() { + var server; + beforeEach(function (done) { + vfsServer({testing: true}, { + "db": mockDb, + "vfs.cache": mockCache, + "api": mockApi, + "connect.render": mockRender, + "connect": mockConnect, + }, function (err, _server) { + if (err) return done(err); + server = _server["vfs.server"]; + done(); + }); + }); + + describe("handlePublish", function() { + beforeEach(function() { + mockCache.remove = sinon.stub(); + }); + + describe("remove_member", function() { + it("Should kill the removed members VFS connection", function (done) { + var vfs = { + id: "9c123", + uid: "123" + }; + var message = JSON.stringify({ + action: "remove_member", + body: { + uid: "123" + } + }); + server.handlePublish(vfs, message); + setTimeout(function() { + assert(mockCache.remove.calledWith(vfs.id)); + done(); + }, 150); + }); + + it("Should not kill the other members VFS connection", function (done) { + var vfs = { + id: "9c123", + uid: "456" + }; + var message = JSON.stringify({ + action: "remove_member", + body: { + uid: "123" + } + }); + server.handlePublish(vfs, message); + setTimeout(function() { + assert.equal(mockCache.remove.callCount, 0); + done(); + }, 150); + }); + }); + + describe("update_member_access", function() { + it("Should kill the members VFS connection so they rejoin with the new access level", function (done) { + var vfs = { + id: "9c123", + uid: "123" + }; + var message = JSON.stringify({ + action: "update_member_access", + body: { + uid: "123" + } + }); + server.handlePublish(vfs, message); + setTimeout(function() { + assert(mockCache.remove.calledWith(vfs.id)); + done(); + }, 150); + }); + }); + + }); + + +}); \ No newline at end of file