mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
basic support for unpublishing individual versions (local only)
This commit is contained in:
parent
6ae26226eb
commit
dafcf8647c
4 changed files with 117 additions and 20 deletions
43
lib/index.js
43
lib/index.js
|
@ -171,48 +171,44 @@ module.exports = function(config_hash) {
|
|||
|
||||
// publishing a package
|
||||
app.put('/:package/:_rev?/:revision?', can('publish'), media('application/json'), expect_json, function(req, res, next) {
|
||||
if (req.params._rev != null && req.params._rev != '-rev') return next('route');
|
||||
var name = req.params.package;
|
||||
if (req.params._rev != null && req.params._rev != '-rev') return next('route')
|
||||
var name = req.params.package
|
||||
|
||||
if (Object.keys(req.body).length == 1 && utils.is_object(req.body.users)) {
|
||||
return next(new UError({
|
||||
// 501 status is more meaningful, but npm doesn't show error message for 5xx
|
||||
status: 404,
|
||||
msg: 'npm star|unstar calls are not implemented',
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
try {
|
||||
var metadata = utils.validate_metadata(req.body, name);
|
||||
var metadata = utils.validate_metadata(req.body, name)
|
||||
} catch(err) {
|
||||
return next(new UError({
|
||||
status: 422,
|
||||
msg: 'bad incoming package data',
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
if (req.params._rev) {
|
||||
return next(new UError({
|
||||
status: 404,
|
||||
msg: 'unimplemented yet, work in progress',
|
||||
}));
|
||||
/* storage.change_package(name, metadata, req.params.revision, function(err) {
|
||||
if (err) return next(err);
|
||||
res.status(201);
|
||||
storage.change_package(name, metadata, req.params.revision, function(err) {
|
||||
if (err) return next(err)
|
||||
res.status(201)
|
||||
return res.send({
|
||||
ok: 'package changed'
|
||||
});
|
||||
});*/
|
||||
})
|
||||
})
|
||||
} else {
|
||||
storage.add_package(name, metadata, function(err) {
|
||||
if (err) return next(err);
|
||||
if (err) return next(err)
|
||||
res.status(201);
|
||||
return res.send({
|
||||
ok: 'created new package'
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// unpublishing an entire package
|
||||
app.delete('/:package/-rev/*', can('publish'), function(req, res, next) {
|
||||
|
@ -225,6 +221,17 @@ module.exports = function(config_hash) {
|
|||
});
|
||||
});
|
||||
|
||||
// removing a tarball
|
||||
app.delete('/:package/-/:filename/-rev/:revision', can('publish'), function(req, res, next) {
|
||||
storage.remove_tarball(req.params.package, req.params.filename, req.params.revision, function(err) {
|
||||
if (err) return next(err);
|
||||
res.status(201);
|
||||
return res.send({
|
||||
ok: 'tarball removed'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// uploading package tarball
|
||||
app.put('/:package/-/:filename/*', can('publish'), media('application/octet-stream'), function(req, res, next) {
|
||||
var name = req.params.package;
|
||||
|
|
|
@ -61,6 +61,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
|
|||
|
||||
Storage.prototype.remove_package = function(name, callback) {
|
||||
var self = this
|
||||
self.logger.info({name: name}, 'unpublishing @{name} (all)')
|
||||
self.storage.read_json(name + '/' + info_file, function(err, data) {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
|
@ -215,6 +216,57 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback)
|
|||
}, callback)
|
||||
}
|
||||
|
||||
// currently supports unpublishing only
|
||||
Storage.prototype.change_package = function(name, metadata, revision, callback) {
|
||||
var self = this
|
||||
|
||||
if (!utils.is_object(metadata.versions) || !utils.is_object(metadata['dist-tags'])) {
|
||||
return callback(new UError({
|
||||
status: 422,
|
||||
msg: 'bad data',
|
||||
}))
|
||||
}
|
||||
|
||||
self.update_package(name, function updater(data, cb) {
|
||||
for (var ver in data.versions) {
|
||||
if (metadata.versions[ver] == null) {
|
||||
self.logger.info({name: name, version: ver}, 'unpublishing @{name}@@{version}')
|
||||
delete data.versions[ver]
|
||||
|
||||
for (var file in data._attachments) {
|
||||
if (data._attachments[file].version === ver) {
|
||||
delete data._attachments[file].version
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data['dist-tags'] = metadata['dist-tags']
|
||||
cb()
|
||||
}, function(err) {
|
||||
if (err) return callback(err)
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
Storage.prototype.remove_tarball = function(name, filename, revision, callback) {
|
||||
var self = this
|
||||
|
||||
self.update_package(name, function updater(data, cb) {
|
||||
if (data._attachments[filename]) {
|
||||
delete data._attachments[filename]
|
||||
cb()
|
||||
} else {
|
||||
cb(new UError({
|
||||
status: 404,
|
||||
msg: 'no such file available',
|
||||
}))
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) return callback(err)
|
||||
self.storage.unlink(name + '/' + filename, callback)
|
||||
})
|
||||
}
|
||||
|
||||
Storage.prototype.add_tarball = function(name, filename) {
|
||||
var stream = new mystreams.UploadTarballStream()
|
||||
, _transform = stream._transform
|
||||
|
@ -411,7 +463,7 @@ Storage.prototype._write_package = function(name, json, callback) {
|
|||
// calculate revision a la couchdb
|
||||
if (typeof(json._rev) !== 'string') json._rev = '0-0000000000000000'
|
||||
var rev = json._rev.split('-')
|
||||
json._rev = ((+rev[0] || 0) + 1) + '-' + crypto.pseudoRandomBytes(16).toString('hex')
|
||||
json._rev = ((+rev[0] || 0) + 1) + '-' + crypto.pseudoRandomBytes(8).toString('hex')
|
||||
|
||||
this.storage.write_json(name + '/' + info_file, json, callback)
|
||||
}
|
||||
|
|
|
@ -132,6 +132,24 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback)
|
|||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Change an existing package (i.e. unpublish one version)
|
||||
//
|
||||
// Function changes a package info from local storage and all uplinks with
|
||||
// write access.
|
||||
//
|
||||
// TODO: currently it works only locally
|
||||
//
|
||||
// TODO: if a package is uploaded to uplink1, but upload to uplink2 fails,
|
||||
// we report failure, but package is not removed from uplink1. This might
|
||||
// require manual intervention.
|
||||
//
|
||||
// Used storages: local (write) && uplinks (proxy_publish, write)
|
||||
//
|
||||
Storage.prototype.change_package = function(name, metadata, revision, callback) {
|
||||
return this.local.change_package(name, metadata, revision, callback)
|
||||
}
|
||||
|
||||
//
|
||||
// Remove a package from a system
|
||||
//
|
||||
|
@ -147,7 +165,26 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback)
|
|||
// Used storages: local (write) && uplinks (proxy_publish, write)
|
||||
//
|
||||
Storage.prototype.remove_package = function(name, callback) {
|
||||
return this.local.remove_package(name, callback);
|
||||
return this.local.remove_package(name, callback)
|
||||
}
|
||||
|
||||
//
|
||||
// Remove a tarball from a system
|
||||
//
|
||||
// Function removes a tarball from local storage and all uplinks with
|
||||
// write access. Tarball in question should not be linked to in any existing
|
||||
// versions, i.e. package version should be unpublished first.
|
||||
//
|
||||
// TODO: currently it works only locally
|
||||
//
|
||||
// TODO: if a package is uploaded to uplink1, but upload to uplink2 fails,
|
||||
// we report failure, but package is not removed from uplink1. This might
|
||||
// require manual intervention.
|
||||
//
|
||||
// Used storages: local (write) && uplinks (proxy_publish, write)
|
||||
//
|
||||
Storage.prototype.remove_tarball = function(name, filename, revision, callback) {
|
||||
return this.local.remove_tarball(name, filename, revision, callback)
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -10,6 +10,7 @@ module.exports.validate_name = function(name) {
|
|||
name !== encodeURIComponent(name) ||
|
||||
name.toLowerCase() === "node_modules" ||
|
||||
name.toLowerCase() === "__proto__" ||
|
||||
name.toLowerCase() === "package.json" ||
|
||||
name.toLowerCase() === "favicon.ico"
|
||||
) {
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue