kopia lustrzana https://github.com/c9/core
Merge remote-tracking branch 'origin/master' into all-workspace-load-metrics
Conflicts: .c9/project.settingspull/374/head
commit
17de8dd1d3
118
.eslintrc
118
.eslintrc
|
@ -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" } }]
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
require("amd-loader");
|
||||
|
||||
var Fs = require("fs");
|
||||
var Path = require("path");
|
||||
var exec = require("child_process").exec;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
});
|
|
@ -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() {
|
||||
|
|
10
package.json
10
package.json
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
Ładowanie…
Reference in New Issue