Compare commits

...

21 Commits
0.9.1 ... 1.0.6

Author SHA1 Message Date
fengmk2
7b77f09264 Release 1.0.6 2014-08-02 02:13:44 +08:00
fengmk2
7731b44ab4 WTF moment@2.8.0 missing 2014-08-02 02:13:24 +08:00
fengmk2
4bc6998040 Release 1.0.5 2014-08-02 02:04:36 +08:00
fengmk2
0d28fbde54 fix remove tar test cases 2014-08-02 02:03:59 +08:00
fengmk2
660035c1d5 Merge pull request #401 from cnpm/hotfix-unpublish-version
unpublish pkg@version bug hotfix. fixed #400
2014-08-02 01:57:19 +08:00
fengmk2
f21e5a1c07 unpublish pkg@version bug hotfix. fixed #400 2014-08-02 01:56:32 +08:00
fengmk2
4d20d91965 Release 1.0.4 2014-08-01 18:40:45 +08:00
fengmk2
a3e33850fc hotfix #399 use not exists 2014-08-01 18:39:53 +08:00
fengmk2
d888ef3297 Release 1.0.3 2014-08-01 13:31:54 +08:00
fengmk2
ce4ec7e6e9 Merge pull request #397 from cnpm/list-users-packages
add maintaining packages in user page
2014-08-01 13:19:30 +08:00
dead_horse
fe319b06ba Release 1.0.2 2014-08-01 12:05:54 +08:00
dead_horse
d829600ed0 ~_~ fix response message 2014-08-01 12:05:25 +08:00
dead_horse
4dd59cb300 Release 1.0.1 2014-08-01 12:00:33 +08:00
dead_horse
5ff25474c0 Merge pull request #398 from cnpm/fix-auth
hot fix auth error
2014-08-01 11:58:54 +08:00
dead_horse
6d49a859c6 hot fix auth error 2014-08-01 11:58:23 +08:00
dead_horse
094178c3ca add maintaining packages in user page 2014-08-01 10:47:47 +08:00
fengmk2
63a57b906e Release 1.0.0 2014-08-01 09:26:04 +08:00
fengmk2
a09e6b142d Merge pull request #394 from cnpm/list-pravites
add private package list
2014-08-01 08:55:11 +08:00
dead_horse
bca9341e5d add private package list 2014-08-01 01:43:13 +08:00
fengmk2
71b0662d49 Release 0.9.2 2014-07-30 23:15:11 +08:00
fengmk2
b894c0fa2b hotfix save custom user bug 2014-07-30 23:14:53 +08:00
21 changed files with 346 additions and 105 deletions

View File

@@ -1,3 +1,5 @@
language: node_js
node_js:
- '0.11'
script: "make test-travis"
after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"

View File

@@ -1,4 +1,45 @@
1.0.6 / 2014-08-02
==================
* WTF moment@2.8.0 missing
1.0.5 / 2014-08-02
==================
* unpublish pkg@version bug hotfix. fixed #400
1.0.4 / 2014-08-01
==================
* hotfix #399 use not exists
1.0.3 / 2014-08-01
==================
* add maintaining packages in user page
1.0.2 / 2014-08-01
==================
* ~_~ fix auth error response message
1.0.1 / 2014-08-01
==================
* Merge pull request #398 from cnpm/fix-auth
* hot fix auth error
1.0.0 / 2014-08-01
==================
* add private package list
0.9.2 / 2014-07-30
==================
* hotfix save custom user bug
0.9.1 / 2014-07-30
==================

View File

@@ -44,6 +44,21 @@ test-cov cov: install pretest
$(TESTS)
@./node_modules/.bin/cov coverage
test-travis: install pretest
@NODE_ENV=test node --harmony \
node_modules/.bin/istanbul cover --preserve-comments \
./node_modules/.bin/_mocha \
--report lcovonly \
-- \
--reporter dot \
--timeout $(TIMEOUT) \
--require should \
--require should-http \
--require co-mocha \
--require ./test/init.js \
$(MOCHA_OPTS) \
$(TESTS)
contributors: install
@./node_modules/.bin/contributors -f plain -o AUTHORS

View File

@@ -1,9 +1,22 @@
cnpmjs.org
=======
[![Build Status](https://secure.travis-ci.org/cnpm/cnpmjs.org.svg)](http://travis-ci.org/cnpm/cnpmjs.org) [![Dependency Status](https://gemnasium.com/cnpm/cnpmjs.org.svg)](https://gemnasium.com/cnpm/cnpmjs.org)
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![Gittip][gittip-image]][gittip-url]
[![David deps][david-image]][david-url]
[![NPM](https://nodei.co/npm/cnpmjs.org.svg?downloads=true&stars=true)](https://nodei.co/npm/cnpmjs.org/)
[npm-image]: https://img.shields.io/npm/v/cnpmjs.org.svg?style=flat
[npm-url]: https://npmjs.org/package/cnpmjs.org
[travis-image]: https://img.shields.io/travis/cnpm/cnpmjs.org.svg?style=flat
[travis-url]: https://travis-ci.org/cnpm/cnpmjs.org
[coveralls-image]: https://img.shields.io/coveralls/cnpm/cnpmjs.org.svg?style=flat
[coveralls-url]: https://coveralls.io/r/cnpm/cnpmjs.org?branch=master
[gittip-image]: https://img.shields.io/gittip/fengmk2.svg?style=flat
[gittip-url]: https://www.gittip.com/fengmk2/
[david-image]: https://img.shields.io/david/cnpm/cnpmjs.org.svg?style=flat
[david-url]: https://david-dm.org/cnpm/cnpmjs.org
![logo](https://raw.github.com/cnpm/cnpmjs.org/master/logo.png)

View File

@@ -747,7 +747,7 @@ exports.removeWithVersions = function* (next) {
debug('remove versions: %j, remain versions: %j', removeVersions, remainVersions);
// step 4: remove all the versions which need to remove
yield Module.removeByNameAndVersions(name, removeVersions);
// let removeTar do remove versions from module table
var tags = yield Module.listTags(name);
var removeTags = [];
@@ -785,20 +785,24 @@ exports.removeTar = function* (next) {
var name = this.params.name || this.params[0];
var filename = this.params.filename || this.params[1];
var id = Number(this.params.rev || this.params[2]);
debug('remove tarball with filename: %s, id: %s', filename, id);
// cnpmjs.org-2.0.0.tgz
var version = filename.split(name + '-')[1];
if (version) {
// 2.0.0.tgz
version = version.substring(0, version.lastIndexOf('.tgz'));
}
if (!version) {
return yield* next;
}
debug('remove tarball with filename: %s, version: %s, revert to => rev id: %s', filename, version, id);
var username = this.user.name;
if (isNaN(id)) {
return yield* next;
}
var mod = yield Module.getById(id);
if (!mod || mod.name !== name) {
return yield* next;
}
var isMaintainer = yield* packageService.isMaintainer(name, username);
if (!isMaintainer && !this.user.isAdmin) {
this.status = 403;
this.body = {
@@ -807,9 +811,33 @@ exports.removeTar = function* (next) {
};
return;
}
var key = mod.package.dist && mod.package.dist.key;
var rs = yield [
Module.getById(id),
Module.get(name, version),
];
var revertTo = rs[0];
var mod = rs[1]; // module need to delete
if (!mod || mod.name !== name) {
return yield* next;
}
var key = mod.package && mod.package.dist && mod.package.dist.key;
key = key || common.getCDNKey(mod.name, filename);
yield nfs.remove(key);
if (revertTo && revertTo.package) {
debug('removing key: %s from nfs, revert to %s@%s', key, revertTo.name, revertTo.package.version);
} else {
debug('removing key: %s from nfs, no revert mod', key);
}
try {
yield nfs.remove(key);
} catch (err) {
logger.error(err);
}
// remove version from table
yield Module.removeByNameAndVersions(name, [version]);
debug('removed %s@%s', name, version);
this.body = { ok: true };
};

View File

@@ -242,6 +242,14 @@ exports.displaySync = function* (next) {
});
};
exports.listPrivates = function* () {
var packages = yield Module.listPrivates();
yield this.render('private', {
title: 'private packages',
packages: packages
});
};
function setLicense(pkg) {
var license;
license = pkg.license || pkg.licenses || pkg.licence || pkg.licences;

View File

@@ -44,10 +44,12 @@ exports.display = function* (next) {
return yield* next;
}
user = user || {};
var data = {
name: name,
email: user && user.email,
json: user && user.json || {}
email: user.email,
json: user.json || {}
};
if (data.json.login) {
@@ -72,7 +74,7 @@ exports.display = function* (next) {
title: 'User - ' + name,
packages: packages,
user: data,
lastModified: user.gmt_modified,
lastModified: user && user.gmt_modified,
isAdmin: isAdmin,
scopes: scopes
});

View File

@@ -17,6 +17,11 @@
var debug = require('debug')('cnpmjs.org:middleware:auth');
var UserService = require('../services/user');
/**
* Parse the request authorization
* get the real user
*/
module.exports = function (options) {
return function* auth(next) {
this.user = {};
@@ -40,12 +45,9 @@ module.exports = function (options) {
try {
row = yield* UserService.auth(username, password);
} catch (err) {
this.status = err.status || 500;
this.body = {
error: err.name,
reason: err.message
};
return;
// do not response error here
// many request do not need login
this.user.error = err;
}
if (!row) {

View File

@@ -15,7 +15,17 @@
*/
module.exports = function *login(next) {
if (this.user.error) {
this.status = this.user.error.status || 500;
this.body = {
error: this.user.error.name,
reason: this.user.error.message
};
return;
}
if (!this.user.name) {
this.status = 401;
this.body = {
error: 'unauthorized',

View File

@@ -1,6 +1,6 @@
{
"name": "cnpmjs.org",
"version": "0.9.1",
"version": "1.0.6",
"description": "Private npm registry and web for Enterprise, base on MySQL and Simple Store Service",
"main": "index.js",
"scripts": {
@@ -12,7 +12,7 @@
"dependencies": {
"bytes": "1.0.0",
"cheerio": "0.17.0",
"co": "3.0.6",
"co": "3.1.0",
"co-defer": "0.1.0",
"co-gather": "0.0.1",
"co-read": "0.1.0",
@@ -27,7 +27,7 @@
"graceful": "0.1.0",
"gravatar": "1.0.6",
"humanize-number": "0.0.2",
"koa": "0.8.1",
"koa": "0.8.2",
"koa-limit": "1.0.2",
"koa-markdown": "0.0.3",
"koa-middlewares": "1.2.0",
@@ -35,7 +35,7 @@
"mime": "1.2.11",
"mini-logger": "0.3.0",
"mkdirp": "0.5.0",
"moment": "2.7.0",
"moment": "~2.8.1",
"ms": "0.6.2",
"multiline": "0.3.4",
"mysql": "2.4.1",
@@ -44,7 +44,7 @@
"ready": "0.1.1",
"redis": "0.11.0",
"semver": "3.0.1",
"thunkify-wrap": "1.0.1",
"thunkify-wrap": "1.0.2",
"utility": "0.1.16"
},
"devDependencies": {

View File

@@ -495,63 +495,6 @@ exports.removeByNameAndVersions = function (name, versions, callback) {
mysql.query(DELETE_MODULE_BY_NAME_AND_VERSIONS_SQL, [name, versions], callback);
};
var LIST_BY_AUTH_SQLS = [];
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
distinct(name) AS name
FROM
module
WHERE
author=?
ORDER BY
publish_time DESC
LIMIT
100;
*/}));
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
module_id
FROM
tag
WHERE
tag="latest" AND name IN (?);
*/}));
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
name, description
FROM
module
WHERE
id IN (?)
ORDER BY
publish_time DESC;
*/}));
exports.listByAuthor = function (author, callback) {
var ep = eventproxy.create();
ep.fail(callback);
mysql.query(LIST_BY_AUTH_SQLS[0], [author], ep.done(function (rows) {
if (!rows || rows.length === 0) {
return callback(null, []);
}
ep.emit('names', rows.map(function (r) {
return r.name;
}));
}));
ep.on('names', function (names) {
mysql.query(LIST_BY_AUTH_SQLS[1], [names], ep.done(function (rows) {
if (!rows || rows.length === 0) {
return callback(null, []);
}
ep.emit('ids', rows.map(function (r) {
return r.module_id;
}));
}));
});
ep.on('ids', function (ids) {
mysql.query(LIST_BY_AUTH_SQLS[2], [ids], callback);
});
};
var SEARCH_MODULES_SQL = multiline(function () {;/*
SELECT
module_id
@@ -704,3 +647,102 @@ exports.getAdaptName = function* (name) {
}
return;
};
exports.listPrivates = function* () {
var scopes = config.scopes;
if (!scopes || !scopes.length) {
return [];
}
var privatePackages = config.privatePackages || [];
var args = [];
var sql = 'SELECT module_id AS id FROM tag WHERE tag="latest" AND (';
var wheres = [];
scopes.forEach(function (scope) {
wheres.push('name LIKE ?');
args.push(scope + '%');
});
if (privatePackages.length) {
wheres.push('name in (?)');
args.push(privatePackages);
}
sql = sql + wheres.join(' OR ') + ')';
var ids = yield mysql.query(sql, args);
ids = ids.map(function (row) {
return row.id;
});
if (!ids.length) {
return [];
}
return yield mysql.query(QUERY_MODULES_BY_ID_SQL, [ids]);
};
var LIST_BY_AUTH_SQLS = [];
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
distinct(name) AS name
FROM
module
WHERE
author=?
ORDER BY
publish_time DESC
LIMIT
100;
*/}));
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
name
FROM
module_maintainer
WHERE
user = ?
*/}));
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
module_id
FROM
tag
WHERE
tag="latest" AND name IN (?);
*/}));
LIST_BY_AUTH_SQLS.push(multiline(function () {;/*
SELECT
name, description
FROM
module
WHERE
id IN (?)
ORDER BY
publish_time DESC;
*/}));
exports.listByAuthor = function* (author, callback) {
var names = yield [
mysql.query(LIST_BY_AUTH_SQLS[0], [author]),
mysql.query(LIST_BY_AUTH_SQLS[1], [author])
];
names = names[0].concat(names[1]).map(function (n) {
return n.name;
}).sort();
if (!names.length) {
return [];
}
var ids = yield mysql.query(LIST_BY_AUTH_SQLS[2], [names]);
if (!ids.length) {
return [];
}
ids = ids.map(function (i) {
return i.module_id;
});
return yield mysql.query(LIST_BY_AUTH_SQLS[3], [ids]);
};

View File

@@ -152,7 +152,7 @@ exports.saveNpmUser = function* (user) {
exports.saveCustomUser = function* (data) {
var sql = 'SELECT id, json FROM user WHERE name=?;';
var row = yield mysql.queryOne(sql, [data.user.name]);
var row = yield mysql.queryOne(sql, [data.user.login]);
var salt = data.salt || '0';
var password_sha = data.password_sha || '0';
var ip = data.ip || '0';

View File

@@ -31,6 +31,8 @@ function routes(app) {
app.get('/package/:name', pkg.display);
app.get('/package/:name/:version', pkg.display);
app.get('/privates', pkg.listPrivates);
app.get(/\/browse\/keyword\/(@[\w\-\.]+\/[\w\-\.]+)$/, pkg.search);
app.get('/browse/keyword/:word', pkg.search);

View File

@@ -105,6 +105,7 @@ routes(app);
app.on('error', function (err, ctx) {
err.url = err.url || ctx.request.url;
console.log(err.stack);
logger.error(err);
});

View File

@@ -560,7 +560,7 @@ describe('controllers/registry/module/public_module.test.js', function () {
mm(config, 'enablePrivate', false);
mm(config, 'forcePublishWithScope', false);
});
before(function (done) {
beforeEach(function (done) {
mm(config, 'enablePrivate', false);
mm(config, 'forcePublishWithScope', false);
var pkg = utils.getPackage('public-test-delete-download-module', '0.1.9', utils.otherUser);
@@ -569,9 +569,11 @@ describe('controllers/registry/module/public_module.test.js', function () {
.set('content-type', 'application/json')
.set('authorization', utils.otherUserAuth)
.send(pkg)
.expect(201, function (err, res) {
.end(function (err, res) {
should.not.exist(err);
withoutScopeRev = res.body.rev;
if (res.body.rev) {
withoutScopeRev = res.body.rev;
}
done();
});
});
@@ -603,7 +605,7 @@ describe('controllers/registry/module/public_module.test.js', function () {
mm(config, 'enablePrivate', false);
mm(config, 'forcePublishWithScope', true);
});
before(function (done) {
beforeEach(function (done) {
mm(config, 'enablePrivate', false);
mm(config, 'forcePublishWithScope', true);
var pkg = utils.getPackage('@cnpm/public-test-delete-download-module', '0.1.9', utils.otherUser);
@@ -612,9 +614,11 @@ describe('controllers/registry/module/public_module.test.js', function () {
.set('content-type', 'application/json')
.set('authorization', utils.otherUserAuth)
.send(pkg)
.expect(201, function (err, res) {
.end(function (err, res) {
should.not.exist(err);
withScopeRev = res.body.rev;
if (res.body.rev) {
withScopeRev = res.body.rev;
}
done();
});
});

View File

@@ -43,14 +43,14 @@ describe('controllers/sync.test.js', function () {
it('should sync as publish success', function (done) {
request(registryApp)
.del('/utility/-rev/123')
.del('/pedding/-rev/123')
.set('authorization', baseauth)
.end(function (err, res) {
should.not.exist(err);
mm.data(Npm, 'get', require(path.join(fixtures, 'utility.json')));
request(registryApp)
.put('/utility/sync?publish=true&nodeps=true')
.put('/pedding/sync?publish=true&nodeps=true')
.set('authorization', baseauth)
.end(function (err, res) {
should.not.exist(err);
@@ -75,7 +75,7 @@ describe('controllers/sync.test.js', function () {
it('should sync through web success', function (done) {
mm.data(Npm, 'get', require(path.join(fixtures, 'utility.json')));
request(webApp)
.put('/sync/utility')
.put('/sync/pedding')
.end(function (err, res) {
should.not.exist(err);
res.body.should.have.keys('ok', 'logId');
@@ -87,7 +87,7 @@ describe('controllers/sync.test.js', function () {
it('should sync through registry success', function (done) {
mm.data(Npm, 'get', require(path.join(fixtures, 'utility.json')));
request(registryApp)
.put('/utility/sync')
.put('/pedding/sync')
.set('authorization', baseauth)
.end(function (err, res) {
should.not.exist(err);
@@ -100,7 +100,7 @@ describe('controllers/sync.test.js', function () {
it('should get sync log', function (done) {
done = pedding(2, done);
request(registryApp)
.get('/utility/sync/log/' + logIdRegistry)
.get('/pedding/sync/log/' + logIdRegistry)
.end(function (err, res) {
should.not.exist(err);
res.body.should.have.keys('ok', 'log');
@@ -108,7 +108,7 @@ describe('controllers/sync.test.js', function () {
});
request(webApp)
.get('/sync/utility/log/' + logIdWeb)
.get('/sync/pedding/log/' + logIdWeb)
.end(function (err, res) {
should.not.exist(err);
res.body.should.have.keys('ok', 'log');

View File

@@ -25,6 +25,7 @@ var registry = require('../../../servers/registry');
var pkg = require('../../../controllers/web/package');
var SyncModuleWorker = require('../../../proxy/sync_module_worker');
var utils = require('../../utils');
var config = require('../../../config');
var fixtures = path.join(path.dirname(path.dirname(__dirname)), 'fixtures');
@@ -237,4 +238,21 @@ describe('controllers/web/package.test.js', function () {
.expect(/This package has been unpublished\./, done);
});
});
describe('GET /privates', function () {
it('should response no private packages', function (done) {
mm(config, 'scopes', []);
request(app)
.get('/privates')
.expect(/Can not found private package/)
.expect(200, done);
});
it('should response no private packages', function (done) {
request(app)
.get('/privates')
.expect(/Private packages in this registry/)
.expect(200, done);
});
});
});

View File

@@ -14,4 +14,4 @@
* Module dependencies.
*/
var varname = require('modulename');
var koa = require('koa');

View File

@@ -77,7 +77,7 @@ describe('middleware/auth.test.js', function () {
});
request(app)
.get('/-/user/org.couchdb.user:cnpmjstest10')
.put('/-/user/org.couchdb.user:cnpmjstest10/-rev/1')
.set('authorization', 'basic ' + new Buffer('cnpmjstest10:cnpmjstest10').toString('base64'))
.expect({
error: 'UserSeriveAuthError',

View File

@@ -20,6 +20,7 @@ var fs = require('fs');
var path = require('path');
var mysql = require('../../common/mysql');
var Module = require('../../proxy/module');
var config = require('../../config');
var fixtures = path.join(path.dirname(__dirname), 'fixtures');
@@ -144,13 +145,10 @@ describe('proxy/module.test.js', function () {
});
describe('listByAuthor()', function () {
it('should return author recent modules', function (done) {
Module.listByAuthor('fengmk2', function (err, rows) {
should.not.exist(err);
rows.forEach(function (r) {
r.should.have.keys('name', 'description');
});
done();
it('should return author recent modules', function* () {
var rows = yield Module.listByAuthor('fengmk2');
rows.forEach(function (r) {
r.should.have.keys('name', 'description');
});
});
});
@@ -173,4 +171,26 @@ describe('proxy/module.test.js', function () {
yield* Module.removeTagsByNames('foo', ['latest', '1.0']);
});
});
describe('listPrivates()', function () {
it('should response [] if scopes not present', function* () {
mm(config, 'scopes', []);
var modules = yield Module.listPrivates();
modules.should.eql([]);
});
it('should response [] if private modules not present', function* () {
mm(config, 'privatePackages', []);
mm(config, 'scopes', ['@not-exist']);
var modules = yield Module.listPrivates();
modules.should.eql([]);
});
it('should work', function* () {
var modules = yield Module.listPrivates();
modules.forEach(function (m) {
m.should.have.keys(['name', 'description']);
})
});
});
});

33
view/web/private.html Normal file
View File

@@ -0,0 +1,33 @@
<style>
#private .package {
padding: 10px;
font-size: 18px;
border-bottom: 1px solid #ddd;
}
#private .alert a {
font-size: 20px;
}
</style>
<div id="private">
<% if (!packages.length) { %>
<div class="alert alert-warning">
Can not found private package
</div>
<% } else {%>
<h1>
Private packages in this registry
</h1>
<hr />
<% for (var i = 0; i < packages.length; i++) {
var item = packages[i];
%>
<div class="package">
<a href="/package/<%= item.name %>" class="package-name"><%= item.name %></a>
<span class="package-description"><%= item.description %></span>
</div>
<% } %>
<% } %>
</div>