Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Implements changeOwner and changeRequirements
Browse files Browse the repository at this point in the history
  • Loading branch information
dangoor committed Apr 9, 2014
1 parent d0c951d commit f5676fa
Show file tree
Hide file tree
Showing 10 changed files with 773 additions and 234 deletions.
130 changes: 89 additions & 41 deletions lib/repository.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
/*
* Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*
*/


Expand Down Expand Up @@ -59,7 +59,7 @@ var Errors = {
REGISTRY_NOT_LOADED: "REGISTRY_NOT_LOADED",
DUPLICATE_TITLE: "DUPLICATE_TITLE",
UNKNOWN_EXTENSION: "UNKNOWN_EXTENSION",

// These failures do not need to be localized. They are only displayed to people
// running the server.
NOT_CONFIGURED: "Repository not configured!"
Expand Down Expand Up @@ -90,9 +90,9 @@ function titleAlreadyPresent(name, title) {
if (!title) {
return false;
}

title = title.toLowerCase();

var key;
for (key in registry) {
if (registry.hasOwnProperty(key) && key !== name &&
Expand Down Expand Up @@ -181,7 +181,7 @@ function addDownloadDataToPackage(name, version, newDownloads, recentDownloads)

/**
* Adds or updates a package in the repository.
*
*
* The package is validated, the user's authorization is checked, the version
* is checked to ensure that only newer versions of major branches are being uploaded.
* If any of these fail, an Error is sent back to the callback.
Expand All @@ -203,51 +203,51 @@ function addPackage(packagePath, userID, callback) {
callback(err, null);
return;
}

var error;

if (result.errors && result.errors.length) {
error = new Error(Errors.VALIDATION_FAILED);
error.errors = result.errors;
callback(error, null);
return;
}

var name = result.metadata.name;

if (titleAlreadyPresent(name, result.metadata.title)) {
error = new Error(Errors.VALIDATION_FAILED);
error.errors = [[Errors.DUPLICATE_TITLE, result.metadata.title]];
callback(error, null);
return;
}

// Look up the current repository entry to see if this is an add or update
var entry;

if (registry.hasOwnProperty(name)) {
// update, we'll deep clone to hang on to the value
entry = clone(registry[result.metadata.name]);

// Verify that the user is authorized to add this package
if (entry.owner !== userID) {
callback(new Error(Errors.NOT_AUTHORIZED), null);
return;
}

// Verify that this is a higher version number
var newVersion = result.metadata.version;
var lastVersion = entry.versions[entry.versions.length - 1].version;
if (!semver.gt(newVersion, lastVersion)) {
callback(new Error(Errors.BAD_VERSION), null);
return;
}

entry.versions.push({
version: newVersion,
published: new Date().toJSON()
});

entry.metadata = result.metadata;
} else {
// add
Expand All @@ -260,20 +260,20 @@ function addPackage(packagePath, userID, callback) {
}]
};
}

storage.savePackage(entry, packagePath, function (err) {
if (err) {
callback(err, null);
} else {
registry[result.metadata.name] = entry;

// Keep track of the Brackets compatibility information per version
// so that the client can install the right version for the user's copy
// of Brackets
if (result.metadata.engines && result.metadata.engines.brackets) {
entry.versions[entry.versions.length - 1].brackets = result.metadata.engines.brackets;
}

storage.saveRegistry(registry);
callback(null, entry);
}
Expand All @@ -285,11 +285,49 @@ function addPackage(packagePath, userID, callback) {
* Removes extension metadata from the registry. This is the form of "delete package" that we offer
* today.
*
* @param {string} name of the package to remove
* @param {string} userID of the user submitting the request
* @param {function} callback (err) called when the operation is complete
* @param {Object} entry of the package to remove
*/
function deletePackageMetadata(name, userID, callback) {
function deletePackageMetadata(entry) {
delete registry[entry.metadata.name];
}

/**
* Changes the owner of an extension.
*
* @param {Object} entry from the extension registry
* @param {string} newUserID of the new package owner
*/
function changePackageOwner(entry, newUserID) {
entry.owner = newUserID;
}

/**
* Change Brackets version requirements.
*
* @param {Object} entry from the extension registry
* @param {string} requirements semver string for the extension's requirements
*/
function changePackageRequirements(entry, requirements) {
var metadata = entry.metadata;
if (!metadata.engines) {
metadata.engines = {};
}
metadata.engines.brackets = requirements;
}

/**
* Wraps an extension manipulation function to automatically check that the named
* package exists and that the user given has permission to edit. The rest of the
* arguments are passed along to the package function.
*
* The last argument given is assumed to be a callback.
*
* @param {function} func function that performs the actual desired behavior
* @param {string} name extension name
* @param {string} userID owner or admin that is submitting the request
*/
function _packageManipulatorWrapper(func, name, userID) {
var callback = arguments[arguments.length - 1];
var entry = registry[name];
if (!entry) {
callback(new Error(Errors.UNKNOWN_EXTENSION));
Expand All @@ -299,12 +337,20 @@ function deletePackageMetadata(name, userID, callback) {
callback(new Error(Errors.NOT_AUTHORIZED));
return;
}
delete registry[name];

// In the arguments to the package function, the name of the package is replaced by the
// registry entry and we don't pass in the user ID. Any other arguments, including the
// callback, are passed straight through.
var args = [entry],
counter;
for (counter = 3; counter < arguments.length; counter++) {
args.push(arguments[counter]);
}
func.apply(null, args);
storage.saveRegistry(registry);
callback(null);
}


/*
* Sets the configuration in use by this module.
*
Expand Down Expand Up @@ -340,12 +386,14 @@ function getRegistry() {
return registry;
}

exports.Errors = Errors;
exports.addPackage = addPackage;
exports.deletePackageMetadata = deletePackageMetadata;
exports.configure = configure;
exports.getRegistry = getRegistry;
exports.addDownloadDataToPackage = addDownloadDataToPackage;
exports.Errors = Errors;
exports.addPackage = addPackage;
exports.deletePackageMetadata = _.partial(_packageManipulatorWrapper, deletePackageMetadata);
exports.changePackageOwner = _.partial(_packageManipulatorWrapper, changePackageOwner);
exports.changePackageRequirements = _.partial(_packageManipulatorWrapper, changePackageRequirements);
exports.configure = configure;
exports.getRegistry = getRegistry;
exports.addDownloadDataToPackage = addDownloadDataToPackage;

// Testing
exports._updateRecentDownloadsForPackage = updateRecentDownloadsForPackage;
Loading

0 comments on commit f5676fa

Please sign in to comment.