Merge remote-tracking branch 'origin/master' into all-workspace-load-metrics

Conflicts:
	.c9/project.settings
pull/374/head
Tim Robinson 2016-10-06 22:09:00 +00:00
commit 17de8dd1d3
11 zmienionych plików z 258 dodań i 102 usunięć

118
.eslintrc
Wyświetl plik

@ -8,13 +8,18 @@ env:
builtin: true
mocha: true
jasmine: false
es6: false
es6: true
plugins:
- react
extends:
- eslint:recommended
- plugin:react/recommended
rules:
handle-callback-err: 1
max-len: [1, 140, 4, { ignorePattern: "\": " }]
no-debugger: 1
no-undef: 1
no-inner-declarations: [1, "functions"]
@ -22,60 +27,77 @@ rules:
no-new-func: 1
no-new-wrappers: 1
no-cond-assign: [1, "except-parens"]
no-debugger: 3
no-dupe-keys: 3
no-eval: 3
no-dupe-keys: 1
no-eval: 1
no-console: 0
no-func-assign: 1
no-invalid-regexp: 1
no-irregular-whitespace: 3
no-irregular-whitespace: 1
no-negated-in-lhs: 1
no-regex-spaces: 3
no-regex-spaces: 1
no-unreachable: 1
use-isnan: 2
use-isnan: 1
valid-typeof: 1
no-redeclare: 3
no-redeclare: 1
no-with: 1
radix: 3
no-delete-var: 2
no-label-var: 3
no-shadow-restricted-names: 2
handle-callback-err: 1
no-new-require: 2
no-unused-vars: [3, {vars: "all", args: "none"}]
no-undef: 1
semi: 3
no-extra-semi: 3
radix: 1
no-delete-var: 1
no-label-var: 1
no-shadow-restricted-names: 1
no-new-require: 1
no-unused-vars: [1, {vars: "all", args: "none"}]
semi: 1
no-extra-semi: 1
one-var: [1, "never"]
arrow-parens: 1
no-confusing-arrow: 1
camelcase: [1, { properties: "never" }]
id-blacklist: [1, "uname", "cb", "acct"]
default-case: 1
eqeqeq: [1, "smart"]
// React rules
display-name: [1, { acceptTranspilerName: true }]
jsx-curly-spacing: 1
no-deprecated: [1, {react: "0.13.0"}]
no-did-mount-set-state: 1
no-did-update-set-state: 1
no-direct-mutation-state: 1
no-is-mounted: 1
no-unknown-property: 1
prefer-es6-class: [1, "never"]
prop-types: 1
react-in-jsx-scope: 1
self-closing-comp: 1
sort-comp: 1
wrap-multilines: 1
jsx-boolean-value: [1, "always"]
jsx-equals-spacing: 1
jsx-indent-props: 1
jsx-key: 1
jsx-indent: 1
jsx-max-props-per-line: [1, { maximum: 5 }]
jsx-no-bind: 1
jsx-no-duplicate-props: 1
jsx-no-undef: 1
jsx-pascal-case: 1
jsx-uses-react: 1
react/jsx-curly-spacing: 1
react/no-deprecated: 1
react/no-did-mount-set-state: 1
react/no-did-update-set-state: 1
react/no-direct-mutation-state: 1
react/no-is-mounted: 1
react/no-unknown-property: 1
react/prefer-es6-class: 1
react/prop-types: 1
react/react-in-jsx-scope: 1
react/self-closing-comp: 1
react/sort-comp: 1
# This rule is not compatible with eslint < 3
# react/jsx-wrap-multilines: 1
react/jsx-boolean-value: [1, "always"]
react/jsx-equals-spacing: 1
react/jsx-indent-props: 1
react/jsx-key: 1
react/jsx-indent: 1
react/jsx-max-props-per-line: [1, { maximum: 5 }]
react/jsx-no-bind: 1
react/jsx-no-duplicate-props: 1
react/jsx-no-undef: 1
react/jsx-pascal-case: 1
react/jsx-uses-react: 1
default-case: 3
keyword-spacing: [1, {"before": true, "after": true, "overrides": { "catch": {"after": "maybe" } }}]
keyword-spacing: [1, {"before": true, "after": true, "overrides": { "catch": {"after": true } }}]
key-spacing: [1, { beforeColon: false, afterColon: true, mode: "strict" }]
space-in-parens: [1, "never"]
// space-before-function-paren: [3, {"named": "never", "anonymous": "never"}]
spaced-comment: 3
space-infix-ops: [1]
arrow-spacing: 1
generator-star-spacing: [1, {"before": false, "after": true}]
space-before-blocks: [1, "always"]
// TODO: after eslint update in IDE
// space-before-function-paren: [1, {"named": "never", "anonymous": "ignore"}]
// object-curly-newline: [1, { ObjectExpression: { "multiline": true }, "ObjectPattern": "never" }]
// DISABLED: causes issue with define(function() in client-side code
// indent: [1, 4, { SwitchCase: 1, outerIIFEBody: 0, MemberExpression: 1, FunctionDeclaration: { body: 0, parameters: 1 }, FunctionExpression: { body: 0, parameters: 1 } }]
object-curly-spacing: [1, "always", { objectsInObjects: false, arraysInObjects: false }]
spaced-comment: 1
comma-spacing: 1
no-multi-spaces: 1
no-lone-blocks: 1
// valid-jsdoc: [1, { requireReturn: false, requireParamDescription: false, prefer: { "return": "return" } }]

2
node_modules/c9/git.js wygenerowano vendored
Wyświetl plik

@ -1,7 +1,5 @@
"use strict";
require("amd-loader");
var Fs = require("fs");
var Path = require("path");
var exec = require("child_process").exec;

9
node_modules/c9/ratelimit.js wygenerowano vendored
Wyświetl plik

@ -30,8 +30,15 @@ function ratelimit(key, duration, max) {
return true;
}
// Returns a deep value from an object. E.g. resolveValue({user: {id: 5}}, "user.id") === 5
function resolveValue(obj, path) {
return path.split('.').reduce(function(prev, curr) {
return prev ? prev[curr] : undefined;
}, obj);
}
return function(req, res, next) {
var handle = req.params[key];
var handle = resolveValue(req.params, key);
requests[handle] = requests[handle] || [];
if (requests[handle].length >= max) {

64
node_modules/c9/ratelimit_test.js wygenerowano vendored
Wyświetl plik

@ -5,6 +5,7 @@ require("c9/inline-mocha")(module);
var ratelimit = require("./ratelimit");
var assert = require("assert");
var async = require("async");
var sinon = require("sinon");
describe("ratelimit", function() {
@ -31,7 +32,16 @@ describe("ratelimit", function() {
});
});
it("Should work with deep keys", function (done) {
var limiter = ratelimit("user.id", 10, 1);
limiter({params: {user: {id: "hey"}}}, null, function (err) {
assert(!err, err);
limiter({params: {user: {id: "yay"}}}, null, function (err) {
assert(!err, err);
done();
});
});
});
it("Should work again after a delay", function (done) {
var limiter = ratelimit("username", 10, 1);
@ -68,37 +78,27 @@ describe("ratelimit", function() {
});
it("Should expire keys at the correct times", function (done) {
var clock = sinon.useFakeTimers();
var limiter = ratelimit("username", 50, 2);
async.series([
function(next) {
limiter({params: {username: "mario"}}, null, function(err) {
assert(!err, err);
setTimeout(next, 25);
});
},
function (next) {
limiter({params: {username: "mario"}}, null, function(err) {
assert(!err, err);
setTimeout(next, 40);
});
},
function (next) {
limiter({params: {username: "mario"}}, null, function(err) {
assert(!err, err);
limiter({params: {username: "mario"}}, null, function(err) {
assert(err);
assert.equal(err.code, 429);
setTimeout(next, 20);
});
});
},
function (next) {
limiter({params: {username: "mario"}}, null, function(err) {
assert(!err, err);
next();
});
}
], done);
limiter({params: {username: "mario"}}, null, function(err){
assert(!err, err);
});
clock.tick(40);
limiter({params: {username: "mario"}}, null, function(err){
assert(!err, err);
});
clock.tick(45);
limiter({params: {username: "mario"}}, null, function(err){
assert(!err, err);
});
limiter({params: {username: "mario"}}, null, function(err){
assert(err);
assert.equal(err.code, 429);
});
clock.tick(40);
limiter({params: {username: "mario"}}, null, function(err){
assert(!err, err);
});
done();
});
});

10
node_modules/c9/urls_test.js wygenerowano vendored
Wyświetl plik

@ -51,14 +51,6 @@ describe("urls", function() {
assert.equal(settings.ide.baseUrlPattern, "https://ide.$DOMAIN");
});
it("behaves like an architect plugin", function(next) {
urls({}, { "error.logger": urls.mockErrorLogger }, function(err, result) {
assert(!err, err);
assert(result.urls.getBaseUrl);
next();
});
});
it("can get the base url for a request", function() {
var mockRequest = {
host: "preview.c9.io"
@ -87,10 +79,8 @@ describe("urls", function() {
var mockRequest = {
host: "preview.cloud9beta.com"
};
urls.mockErrorLogger.log = sinon.spy();
var baseUrl = urls.getBaseUrl(mockRequest, "https://ide.$DOMAIN", "https://$DOMAIN");
assert.equal(baseUrl, "https://c9.io");
assert(urls.mockErrorLogger.log.called);
});
it("can get the base url in dogfooding mode", function() {

Wyświetl plik

@ -1,7 +1,7 @@
{
"name": "c9",
"description": "New Cloud9 Client",
"version": "3.1.3131",
"version": "3.1.3152",
"author": "Ajax.org B.V. <info@ajax.org>",
"private": true,
"main": "bin/c9",
@ -58,7 +58,7 @@
"c9"
],
"c9plugins": {
"c9.ide.language": "#f55c832376",
"c9.ide.language": "#241bd6b7de",
"c9.ide.language.core": "#bfb5dd2acc",
"c9.ide.language.css": "#46ad561506",
"c9.ide.language.generic": "#b47cbe58f9",
@ -66,17 +66,17 @@
"c9.ide.language.html.diff": "#7d6cecfb90",
"c9.ide.language.javascript": "#a5c1d05394",
"c9.ide.language.javascript.immediate": "#82c426dbca",
"c9.ide.language.javascript.eslint": "#cb9e3f5a8e",
"c9.ide.language.javascript.eslint": "#66c856d7ce",
"c9.ide.language.javascript.tern": "#0545a6385d",
"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",
"c9.ide.find.replace": "#8468067976",
"c9.ide.run.debug": "#f10c7e7d19",
"c9.ide.run.debug": "#8963fb45c4",
"c9.automate": "#47e2c429c9",
"c9.ide.ace.emmet": "#6dc4585e02",
"c9.ide.ace.gotoline": "#d33220b1e0",

Wyświetl plik

@ -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");
};

Wyświetl plik

@ -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() {

Wyświetl plik

@ -65,7 +65,7 @@
display: none;
}
.c9-menu-btn.nosize .icon { background-size: auto !important; }
.c9-menu-btn.nosize .icon { background-size: auto; }
.c9-menu-btn.preferences{
padding: @preference-menu-button-padding !important;
@ -116,4 +116,4 @@
.c9-menu-btn.c9btn.offline{
color: #d22a3f;
text-shadow: 0 1px black;
}
}

Wyświetl plik

@ -309,7 +309,7 @@ var HoverLink = function(editor) {
else if (prompt.command === "git") { // git status
var prefix = line.substr(0, match.start);
if (match.start + value.length == line.length
&& /^(#|[ MDR?A]{2})\s+([\w\s]+:\s+)?$/.test(prefix)
&& /^(#|[ MDRU?A]{2})\s+([\w\s]+:\s+)?$/.test(prefix)
) {
match.type = "path";
} else {

Wyświetl plik

@ -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);
});
});
});
});