mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-04-01 02:42:23 -05:00
Merge pull request #1248 from vip30/4.x
feat: add star and unstar api for 4.x
This commit is contained in:
commit
c9c0aa481d
11 changed files with 175 additions and 15 deletions
|
@ -56,7 +56,7 @@
|
|||
"@material-ui/core": "3.9.0",
|
||||
"@material-ui/icons": "3.0.2",
|
||||
"@verdaccio/babel-preset": "0.0.4",
|
||||
"@verdaccio/types": "4.1.4",
|
||||
"@verdaccio/types": "5.0.0-beta.3",
|
||||
"autosuggest-highlight": "3.1.1",
|
||||
"bundlesize": "0.17.1",
|
||||
"codecov": "3.2.0",
|
||||
|
@ -178,7 +178,8 @@
|
|||
"preferGlobal": true,
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && commitlint -e $GIT_PARAMS"
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "commitlint -e $GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -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 {
|
||||
|
|
64
src/api/endpoint/api/star.js
Normal file
64
src/api/endpoint/api/star.js
Normal 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);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -46,3 +46,26 @@ exports[`Publish endpoints - publish package should change the existing package
|
|||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Publish endpoints - publish package should star a package 1`] = `
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"verdaccio",
|
||||
Object {
|
||||
"users": Object {
|
||||
"verdaccio": true,
|
||||
},
|
||||
},
|
||||
"15-e53a77096b0ee33e",
|
||||
[Function],
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -254,11 +254,30 @@ describe('Publish endpoints - publish package', () => {
|
|||
expect(next).toHaveBeenCalledWith(new Error(API_ERROR.BAD_PACKAGE_DATA));
|
||||
});
|
||||
|
||||
test('should throw an error for un-implemented star calls', () => {
|
||||
const storage = {};
|
||||
req.body._rev = REVISION_MOCK;
|
||||
req.body.users = {};
|
||||
test('should star a package', () => {
|
||||
const storage = {
|
||||
changePackage: jest.fn(),
|
||||
getPackage({ name, req, callback }) {
|
||||
callback(null, {
|
||||
users: {},
|
||||
});
|
||||
},
|
||||
};
|
||||
req = {
|
||||
params: {
|
||||
package: 'verdaccio',
|
||||
},
|
||||
body: {
|
||||
_rev: REVISION_MOCK,
|
||||
users: {
|
||||
verdaccio: true,
|
||||
},
|
||||
},
|
||||
remote_user: {
|
||||
name: 'verdaccio',
|
||||
},
|
||||
};
|
||||
publishPackage(storage)(req, res, next);
|
||||
expect(next).toHaveBeenCalledWith(new Error('npm star| un-star calls are not implemented'));
|
||||
expect(storage.changePackage).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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' };
|
||||
|
|
7
test/unit/partials/star-api.js
Normal file
7
test/unit/partials/star-api.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const json = {
|
||||
"_id": "@scope\/pk1-test",
|
||||
"_rev": "4-6abcdb4efd41a576",
|
||||
"users": {}
|
||||
}
|
||||
|
||||
module.exports = json;
|
|
@ -1372,10 +1372,10 @@
|
|||
resolved "https://registry.verdaccio.org/@verdaccio%2fstreams/-/streams-2.0.0-beta.0.tgz#af8c7e673a3c368deacc8024c6f5671aa2ec32ac"
|
||||
integrity sha512-EdVF6RP0abRNT0RfgLCsqLNv7FOpm+BpzMZoaQuQGHSBQRj7OTM8ft5mpbJ40rYVXKv6D8xyU0vUnoRl09ah6g==
|
||||
|
||||
"@verdaccio/types@4.1.4":
|
||||
version "4.1.4"
|
||||
resolved "https://registry.verdaccio.org/@verdaccio%2ftypes/-/types-4.1.4.tgz#6144410b9fd63d916aa279378a4946c701a82586"
|
||||
integrity sha512-0kNIQvMakoHIk1dpgnXVgQ5qwxJGTtMpJkLZKiN5WpLi5yuQtjc+kD/0EWDV4164pKg1KUU6YFLpbcXWxR8zvQ==
|
||||
"@verdaccio/types@5.0.0-beta.3":
|
||||
version "5.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/types/-/types-5.0.0-beta.3.tgz#f6c9fd31a40b2be96fe080c49d7f4a1239413318"
|
||||
integrity sha512-qPwE0bjDhXXVK7Gwg0O6RargAE7/AseVcZhcZEnf25RAra5ZL3MiM0dUUlierMc9XcPVjVHwTasAnF54Qmz9bg==
|
||||
|
||||
"@webassemblyjs/ast@1.7.8":
|
||||
version "1.7.8"
|
||||
|
|
Loading…
Add table
Reference in a new issue