0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-30 22:34:10 -05:00

feat: add star and unstar api for 4.x

This commit is contained in:
vip30 2019-03-09 11:16:44 +08:00
parent 9c01aa4072
commit 1ab7c504ec
7 changed files with 121 additions and 4 deletions

View file

@ -11,6 +11,7 @@ import { API_MESSAGE, HEADERS, DIST_TAGS, API_ERROR, HTTP_STATUS } from '../../.
import { validateMetadata, isObject, ErrorCode } from '../../../lib/utils';
import { media, expectJson, allow } from '../../middleware';
import { notify } from '../../../lib/notify';
import star from './star';
import type { Router } from 'express';
import type { Config, Callback, MergeTags, Version } from '@verdaccio/types';
@ -40,6 +41,7 @@ export default function publish(router: Router, auth: IAuth, storage: IStorageHa
* Publish a package
*/
export function publishPackage(storage: IStorageHandler, config: Config) {
const starApi = star(storage);
return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
const packageName = req.params.package;
/**
@ -138,7 +140,7 @@ export function publishPackage(storage: IStorageHandler, config: Config) {
};
if (Object.prototype.hasOwnProperty.call(req.body, '_rev') && isObject(req.body.users)) {
return next(ErrorCode.getNotFound('npm star| un-star calls are not implemented'));
return starApi(req, res, next);
}
try {

View file

@ -0,0 +1,64 @@
// @flow
import { USERS, HTTP_STATUS } from '../../../lib/constants';
import type {$Response} from 'express';
import type {$RequestExtend, $NextFunctionVer, IStorageHandler} from '../../../../types';
import _ from 'lodash';
export default function(storage: IStorageHandler) {
const validateInputs = (newUsers, localUsers, username, isStar) => {
const isExistlocalUsers = _.isNil(localUsers[username]) === false;
if (isStar && isExistlocalUsers && localUsers[username]) {
return true;
} else if (!isStar && isExistlocalUsers) {
return false;
} else if (!isStar && !isExistlocalUsers) {
return true;
} else {
return false;
}
};
return (req: $RequestExtend, res: $Response, next: $NextFunctionVer): void => {
const name = req.params.package;
const afterChangePackage = function(err) {
if (err) {
return next(err);
}
res.status(HTTP_STATUS.OK);
next({
success: true,
});
};
storage.getPackage({
name,
req,
callback: function(err, info) {
if (err) {
return next(err);
}
const newStarUser = req.body[USERS];
const remoteUsername = req.remote_user.name;
const localStarUsers = info[USERS];
// Check is star or unstar
const isStar = Object.keys(newStarUser).includes(remoteUsername);
if (_.isNil(localStarUsers) === false && validateInputs(newStarUser, localStarUsers, remoteUsername, isStar)) {
return afterChangePackage();
}
const users = isStar ? {
...localStarUsers,
[remoteUsername]: true,
} : _.reduce(localStarUsers, (users, value, key) => {
if (key !== remoteUsername) {
users[key] = value;
}
return users;
}, {});
storage.changePackage(name, { ...info, users}, req.body._rev, function(err) {
afterChangePackage(err);
});
},
});
};
}

View file

@ -10,6 +10,7 @@ export const DEFAULT_DOMAIN: string = 'localhost';
export const TIME_EXPIRATION_24H: string = '24h';
export const TIME_EXPIRATION_7D: string = '7d';
export const DIST_TAGS = 'dist-tags';
export const USERS = 'users';
export const DEFAULT_MIN_LIMIT_PASSWORD: number = 3;
export const DEFAULT_USER = 'Anonymous';

View file

@ -8,7 +8,7 @@ import UrlNode from 'url';
import _ from 'lodash';
import { ErrorCode, isObject, getLatestVersion, tagVersion, validateName } from './utils';
import { generatePackageTemplate, normalizePackage, generateRevision, getLatestReadme, cleanUpReadme, normalizeContributors } from './storage-utils';
import { API_ERROR, DIST_TAGS, STORAGE } from './constants';
import { API_ERROR, DIST_TAGS, STORAGE, USERS } from './constants';
import { createTarballHash } from './crypto-utils';
import { prepareSearchPackage } from './storage-utils';
import loadPlugin from '../lib/plugin-loader';
@ -334,6 +334,7 @@ class LocalStorage implements IStorage {
}
}
localData[USERS] = incomingPkg[USERS];
localData[DIST_TAGS] = incomingPkg[DIST_TAGS];
cb();
},

View file

@ -10,7 +10,7 @@ import { generateRandomHexString } from '../lib/crypto-utils';
import type { Package, Version, Author } from '@verdaccio/types';
import type { IStorage } from '../../types';
import { API_ERROR, HTTP_STATUS, DIST_TAGS, STORAGE } from './constants';
import { API_ERROR, HTTP_STATUS, DIST_TAGS, USERS, STORAGE } from './constants';
export function generatePackageTemplate(name: string): Package {
return {
@ -18,6 +18,7 @@ export function generatePackageTemplate(name: string): Package {
name,
versions: {},
time: {},
[USERS]: {},
[DIST_TAGS]: {},
_uplinks: {},
_distfiles: {},
@ -97,7 +98,7 @@ export function normalizeContributors(contributors: Array<Author>): Array<Author
return contributors;
}
export const WHITELIST = ['_rev', 'name', 'versions', 'dist-tags', 'readme', 'time', '_id'];
export const WHITELIST = ['_rev', 'name', 'versions', 'dist-tags', 'readme', 'time', '_id', 'users'];
export function cleanUpLinksRef(keepUpLinkData: boolean, result: Package): Package {
const propertyToKeep = [...WHITELIST];

View file

@ -5,6 +5,7 @@ import rimraf from 'rimraf';
import configDefault from '../partials/config/index';
import publishMetadata from '../partials/publish-api';
import starMetadata from '../partials/star-api';
import endPointAPI from '../../../src/api/index';
import {HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, API_MESSAGE, TOKEN_BEARER} from '../../../src/lib/constants';
@ -561,6 +562,46 @@ describe('endpoint unit test', () => {
});
});
describe('should test star api', () => {
test('should star a package', (done) => {
request(app)
.put('/@scope%2fpk1-test')
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
.send(JSON.stringify({
...starMetadata,
users: {
[credentials.name]: true
}
}))
.expect(HTTP_STATUS.OK)
.end(function(err, res) {
if (err) {
expect(err).toBeNull();
return done(err);
}
expect(res.body.success).toBeDefined();
expect(res.body.success).toBeTruthy();
done();
});
});
test('should unstar a package', (done) => {
request(app)
.put('/@scope%2fpk1-test')
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
.send(JSON.stringify(starMetadata))
.expect(HTTP_STATUS.OK)
.end(function(err, res) {
if (err) {
expect(err).toBeNull();
return done(err);
}
expect(res.body.success).toBeDefined();
expect(res.body.success).toBeTruthy();
done();
});
});
});
test('should unpublish a new package with credentials', async (done) => {
const credentials = { name: 'jota_unpublish', password: 'secretPass' };

View file

@ -0,0 +1,7 @@
const json = {
"_id": "@scope\/pk1-test",
"_rev": "4-6abcdb4efd41a576",
"users": {}
}
module.exports = json;