Add aggregate results by entityRef
Signed-off-by: Roohn <tol.ronald@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-entity-feedback': minor
|
||||
'@backstage/plugin-entity-feedback-backend': patch
|
||||
'@backstage/plugin-entity-feedback-common': patch
|
||||
---
|
||||
|
||||
Added an endpoint to fetch anonymous aggregated results from an entity
|
||||
@@ -258,6 +258,22 @@ describe('createRouter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /ratings/:entityRef/aggregate', () => {
|
||||
it('should get aggregated ratings for an entity correctly', async () => {
|
||||
const response = await request(app)
|
||||
.get('/ratings/component%3Adefault%2Fservice/aggregate')
|
||||
.send();
|
||||
expect(mockDbHandler.getRatings).toHaveBeenCalledWith(
|
||||
'component:default/service',
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual({
|
||||
DISLIKE: 1,
|
||||
LIKE: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /responses/:entityRef', () => {
|
||||
it('should record a response correctly', async () => {
|
||||
const body = { response: 'blah', comments: 'feedback', consent: true };
|
||||
|
||||
@@ -25,7 +25,10 @@ import {
|
||||
getBearerTokenFromAuthorizationHeader,
|
||||
IdentityApi,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
import { EntityRatingsData } from '@backstage/plugin-entity-feedback-common';
|
||||
import {
|
||||
EntityRatingsData,
|
||||
Ratings,
|
||||
} from '@backstage/plugin-entity-feedback-common';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
@@ -167,6 +170,19 @@ export async function createRouter(
|
||||
res.json(ratings.filter(r => accessibleEntityRefs.includes(r.userRef)));
|
||||
});
|
||||
|
||||
router.get('/ratings/:entityRef/aggregate', async (req, res) => {
|
||||
const entityRatings = (
|
||||
await dbHandler.getRatings(req.params.entityRef)
|
||||
).reduce((ratings: Ratings, { rating }) => {
|
||||
ratings[rating] = ratings[rating] ?? 0;
|
||||
ratings[rating]++;
|
||||
|
||||
return ratings;
|
||||
}, {});
|
||||
|
||||
res.json(entityRatings);
|
||||
});
|
||||
|
||||
router.post('/responses/:entityRef', async (req, res) => {
|
||||
const user = await identity.getIdentity({ request: req });
|
||||
const { response, comments, consent } = req.body;
|
||||
|
||||
@@ -10,9 +10,7 @@ export interface EntityRatingsData {
|
||||
// (undocumented)
|
||||
entityTitle?: string;
|
||||
// (undocumented)
|
||||
ratings: {
|
||||
[ratingValue: string]: number;
|
||||
};
|
||||
ratings: Ratings;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -38,4 +36,10 @@ export interface Rating {
|
||||
// (undocumented)
|
||||
userRef: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface Ratings {
|
||||
// (undocumented)
|
||||
[ratingValue: string]: number;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -40,13 +40,18 @@ export interface FeedbackResponse {
|
||||
userRef: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Ratings {
|
||||
[ratingValue: string]: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface EntityRatingsData {
|
||||
entityRef: string;
|
||||
entityTitle?: string;
|
||||
ratings: {
|
||||
[ratingValue: string]: number;
|
||||
};
|
||||
ratings: Ratings;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { EntityRatingsData } from '@backstage/plugin-entity-feedback-common';
|
||||
import { FeedbackResponse } from '@backstage/plugin-entity-feedback-common';
|
||||
import { FetchApi } from '@backstage/core-plugin-api';
|
||||
import { Rating } from '@backstage/plugin-entity-feedback-common';
|
||||
import { Ratings } from '@backstage/plugin-entity-feedback-common';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
@@ -22,6 +23,7 @@ export interface EntityFeedbackApi {
|
||||
getAllRatings(): Promise<EntityRatingsData[]>;
|
||||
// (undocumented)
|
||||
getOwnedRatings(ownerRef: string): Promise<EntityRatingsData[]>;
|
||||
getRatingAggregates(entityRef: string): Promise<Ratings>;
|
||||
// (undocumented)
|
||||
getRatings(entityRef: string): Promise<Omit<Rating, 'entityRef'>[]>;
|
||||
// (undocumented)
|
||||
@@ -48,6 +50,8 @@ export class EntityFeedbackClient implements EntityFeedbackApi {
|
||||
// (undocumented)
|
||||
getOwnedRatings(ownerRef: string): Promise<EntityRatingsData[]>;
|
||||
// (undocumented)
|
||||
getRatingAggregates(entityRef: string): Promise<Ratings>;
|
||||
// (undocumented)
|
||||
getRatings(entityRef: string): Promise<Omit<Rating, 'entityRef'>[]>;
|
||||
// (undocumented)
|
||||
getResponses(
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
EntityRatingsData,
|
||||
FeedbackResponse,
|
||||
Rating,
|
||||
Ratings,
|
||||
} from '@backstage/plugin-entity-feedback-common';
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,11 @@ export interface EntityFeedbackApi {
|
||||
|
||||
getRatings(entityRef: string): Promise<Omit<Rating, 'entityRef'>[]>;
|
||||
|
||||
/**
|
||||
* Returns anonymized aggregated results for one entityRef
|
||||
*/
|
||||
getRatingAggregates(entityRef: string): Promise<Ratings>;
|
||||
|
||||
recordResponse(
|
||||
entityRef: string,
|
||||
response: Omit<FeedbackResponse, 'entityRef' | 'userRef'>,
|
||||
|
||||
@@ -121,6 +121,24 @@ describe('EntityFeedbackClient', () => {
|
||||
expect(response).toEqual(ratings);
|
||||
});
|
||||
|
||||
it('getRatingAggregates', async () => {
|
||||
const ratings = { LIKE: 3, DISLIKE: 5 };
|
||||
|
||||
server.use(
|
||||
rest.get(
|
||||
`${mockBaseUrl}/ratings/${encodeURIComponent(
|
||||
'component:default/service',
|
||||
)}/aggregate`,
|
||||
(_, res, ctx) => res(ctx.json(ratings)),
|
||||
),
|
||||
);
|
||||
|
||||
const response = await client.getRatingAggregates(
|
||||
'component:default/service',
|
||||
);
|
||||
expect(response).toEqual(ratings);
|
||||
});
|
||||
|
||||
it('recordResponse', async () => {
|
||||
expect.assertions(1);
|
||||
const response = {
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
EntityRatingsData,
|
||||
FeedbackResponse,
|
||||
Rating,
|
||||
Ratings,
|
||||
} from '@backstage/plugin-entity-feedback-common';
|
||||
|
||||
import { EntityFeedbackApi } from './EntityFeedbackApi';
|
||||
@@ -97,6 +98,22 @@ export class EntityFeedbackClient implements EntityFeedbackApi {
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
async getRatingAggregates(entityRef: string): Promise<Ratings> {
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('entity-feedback');
|
||||
const resp = await this.fetchApi.fetch(
|
||||
`${baseUrl}/ratings/${encodeURIComponent(entityRef)}/aggregate`,
|
||||
{
|
||||
method: 'GET',
|
||||
},
|
||||
);
|
||||
|
||||
if (!resp.ok) {
|
||||
throw await ResponseError.fromResponse(resp);
|
||||
}
|
||||
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
async recordResponse(
|
||||
entityRef: string,
|
||||
response: Omit<FeedbackResponse, 'entityRef' | 'userRef'>,
|
||||
|
||||
Reference in New Issue
Block a user