mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-30 22:34:10 -05:00
feat: add stars api
This commit is contained in:
parent
9bc9597413
commit
75c0e1e4ec
5 changed files with 77 additions and 2 deletions
|
@ -157,7 +157,7 @@ Verdaccio aims to support all features of a standard npm client that make sense
|
||||||
|
|
||||||
- Searching (npm search) - **supported** (cli / browser)
|
- Searching (npm search) - **supported** (cli / browser)
|
||||||
- Ping (npm ping) - **supported**
|
- Ping (npm ping) - **supported**
|
||||||
- Starring (npm star, npm unstar) - not supported, *PR-welcome*
|
- Starring (npm star, npm unstar, npm stars) - **supported**
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|
32
src/api/endpoint/api/stars.js
Normal file
32
src/api/endpoint/api/stars.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { USERS, HTTP_STATUS } from '../../../lib/constants';
|
||||||
|
import type { $Response, Router } from 'express';
|
||||||
|
import type { $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types';
|
||||||
|
import type { Package } from '@verdaccio/types';
|
||||||
|
|
||||||
|
export default function(route: Router, storage: IStorageHandler) {
|
||||||
|
route.get(
|
||||||
|
'/-/_view/starredByUser',
|
||||||
|
(req: $RequestExtend, res: $Response, next: $NextFunctionVer): void => {
|
||||||
|
const remoteUsername = req.remote_user.name;
|
||||||
|
storage.getLocalDatabase((err, localPackages: Package[]) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
const filteredPackages = localPackages.filter(
|
||||||
|
localPackage => (localPackage[USERS] ? Object.keys(localPackage[USERS]).indexOf(remoteUsername) >= 0 : false)
|
||||||
|
);
|
||||||
|
res.status(HTTP_STATUS.OK);
|
||||||
|
next({
|
||||||
|
rows: filteredPackages.map(filteredPackage => ({
|
||||||
|
value: filteredPackage.name,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import distTags from './api/dist-tags';
|
||||||
import publish from './api/publish';
|
import publish from './api/publish';
|
||||||
import search from './api/search';
|
import search from './api/search';
|
||||||
import pkg from './api/package';
|
import pkg from './api/package';
|
||||||
|
import stars from './api/stars';
|
||||||
import profile from './api/v1/profile';
|
import profile from './api/v1/profile';
|
||||||
|
|
||||||
const { match, validateName, validatePackage, encodeScopePackage, antiLoop } = require('../middleware');
|
const { match, validateName, validatePackage, encodeScopePackage, antiLoop } = require('../middleware');
|
||||||
|
@ -55,6 +56,7 @@ export default function(config: Config, auth: IAuth, storage: IStorageHandler) {
|
||||||
distTags(app, auth, storage);
|
distTags(app, auth, storage);
|
||||||
publish(app, auth, storage, config);
|
publish(app, auth, storage, config);
|
||||||
ping(app);
|
ping(app);
|
||||||
|
stars(app, storage);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,12 +375,14 @@ class Storage implements IStorageHandler {
|
||||||
self.localStorage.getPackageMetadata(locals[itemPkg], function(err, info) {
|
self.localStorage.getPackageMetadata(locals[itemPkg], function(err, info) {
|
||||||
if (_.isNil(err)) {
|
if (_.isNil(err)) {
|
||||||
const latest = info[DIST_TAGS].latest;
|
const latest = info[DIST_TAGS].latest;
|
||||||
|
|
||||||
if (latest && info.versions[latest]) {
|
if (latest && info.versions[latest]) {
|
||||||
const version = info.versions[latest];
|
const version = info.versions[latest];
|
||||||
const time = info.time[latest];
|
const time = info.time[latest];
|
||||||
version.time = time;
|
version.time = time;
|
||||||
|
|
||||||
|
// Add for stars api
|
||||||
|
version.users = info.users;
|
||||||
|
|
||||||
packages.push(version);
|
packages.push(version);
|
||||||
} else {
|
} else {
|
||||||
self.logger.warn({ package: locals[itemPkg] }, 'package @{package} does not have a "latest" tag?');
|
self.logger.warn({ package: locals[itemPkg] }, 'package @{package} does not have a "latest" tag?');
|
||||||
|
|
|
@ -602,6 +602,45 @@ describe('endpoint unit test', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should retrieve stars list with credentials', async (done) => {
|
||||||
|
const credentials = { name: 'star_user', password: 'secretPass' };
|
||||||
|
const token = await getNewToken(request(app), credentials);
|
||||||
|
request(app)
|
||||||
|
.put('/@scope%2fpk1-test')
|
||||||
|
.set('authorization', buildToken(TOKEN_BEARER, token))
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
request(app)
|
||||||
|
.get('/-/_view/starredByUser')
|
||||||
|
.set('authorization', buildToken(TOKEN_BEARER, token))
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify({
|
||||||
|
key: [credentials.name]
|
||||||
|
}))
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
expect(err).toBeNull();
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
expect(res.body.rows).toBeDefined();
|
||||||
|
expect(res.body.rows.length).toBeGreaterThan(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('should unpublish a new package with credentials', async (done) => {
|
test('should unpublish a new package with credentials', async (done) => {
|
||||||
|
|
||||||
const credentials = { name: 'jota_unpublish', password: 'secretPass' };
|
const credentials = { name: 'jota_unpublish', password: 'secretPass' };
|
||||||
|
|
Loading…
Reference in a new issue