-
-
Notifications
You must be signed in to change notification settings - Fork 721
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: project status backend structure (#8630)
Adding project status schema definition, controller, service, e2e test. Next PR will add functionality for activity object. --------- Co-authored-by: Thomas Heartman <[email protected]>
- Loading branch information
1 parent
c9a564a
commit c9dc526
Showing
11 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
src/lib/features/project-status/createProjectStatusService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import type { Db, IUnleashConfig } from '../../server-impl'; | ||
import { ProjectStatusService } from './project-status-service'; | ||
|
||
export const createProjectStatusService = ( | ||
db: Db, | ||
config: IUnleashConfig, | ||
): ProjectStatusService => { | ||
return new ProjectStatusService(); | ||
}; | ||
|
||
export const createFakeProjectStatusService = () => { | ||
const projectStatusService = new ProjectStatusService(); | ||
|
||
return { | ||
projectStatusService, | ||
}; | ||
}; |
71 changes: 71 additions & 0 deletions
71
src/lib/features/project-status/project-status-controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import type { Response } from 'express'; | ||
import Controller from '../../routes/controller'; | ||
import { | ||
type IFlagResolver, | ||
type IProjectParam, | ||
type IUnleashConfig, | ||
type IUnleashServices, | ||
NONE, | ||
serializeDates, | ||
} from '../../types'; | ||
|
||
import { getStandardResponses } from '../../openapi/util/standard-responses'; | ||
import type { OpenApiService } from '../../services'; | ||
import type { IAuthRequest } from '../../routes/unleash-types'; | ||
import { | ||
createResponseSchema, | ||
projectStatusSchema, | ||
type ProjectStatusSchema, | ||
} from '../../openapi'; | ||
import type { ProjectStatusService } from './project-status-service'; | ||
|
||
export default class ProjectStatusController extends Controller { | ||
private projectStatusService: ProjectStatusService; | ||
|
||
private openApiService: OpenApiService; | ||
|
||
private flagResolver: IFlagResolver; | ||
|
||
constructor(config: IUnleashConfig, services: IUnleashServices) { | ||
super(config); | ||
this.projectStatusService = services.projectStatusService; | ||
this.openApiService = services.openApiService; | ||
this.flagResolver = config.flagResolver; | ||
|
||
this.route({ | ||
method: 'get', | ||
path: '/:projectId/status', | ||
handler: this.getProjectStatus, | ||
permission: NONE, | ||
middleware: [ | ||
this.openApiService.validPath({ | ||
tags: ['Projects'], | ||
operationId: 'getProjectStatus', | ||
summary: 'Get project status', | ||
description: | ||
'This endpoint returns information on the status the project, including activities, health, resources, and aggregated flag lifecycle data.', | ||
responses: { | ||
200: createResponseSchema('projectStatusSchema'), | ||
...getStandardResponses(401, 403, 404), | ||
}, | ||
}), | ||
], | ||
}); | ||
} | ||
|
||
async getProjectStatus( | ||
req: IAuthRequest<IProjectParam, unknown, unknown, unknown>, | ||
res: Response<ProjectStatusSchema>, | ||
): Promise<void> { | ||
const { projectId } = req.params; | ||
const status: ProjectStatusSchema = | ||
await this.projectStatusService.getProjectStatus(projectId); | ||
|
||
this.openApiService.respondWithValidation( | ||
200, | ||
res, | ||
projectStatusSchema.$id, | ||
serializeDates(status), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import type { ProjectStatusSchema } from '../../openapi'; | ||
|
||
export class ProjectStatusService { | ||
constructor() {} | ||
|
||
async getProjectStatus(projectId: string): Promise<ProjectStatusSchema> { | ||
return { activityCountByDate: [{ date: '2024-09-11', count: 0 }] }; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/lib/features/project-status/projects-status.e2e.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init'; | ||
import { | ||
type IUnleashTest, | ||
setupAppWithCustomConfig, | ||
} from '../../../test/e2e/helpers/test-helper'; | ||
import getLogger from '../../../test/fixtures/no-logger'; | ||
|
||
let app: IUnleashTest; | ||
let db: ITestDb; | ||
|
||
beforeAll(async () => { | ||
db = await dbInit('projects_status', getLogger); | ||
app = await setupAppWithCustomConfig( | ||
db.stores, | ||
{ | ||
experimental: { | ||
flags: { | ||
strictSchemaValidation: true, | ||
}, | ||
}, | ||
}, | ||
db.rawDatabase, | ||
); | ||
}); | ||
|
||
afterAll(async () => { | ||
await app.destroy(); | ||
await db.destroy(); | ||
}); | ||
|
||
test('project insights happy path', async () => { | ||
const { body } = await app.request | ||
.get('/api/admin/projects/default/status') | ||
.expect('Content-Type', /json/) | ||
.expect(200); | ||
|
||
expect(body).toMatchObject({ | ||
activityCountByDate: [{ date: '2024-09-11', count: 0 }], | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { FromSchema } from 'json-schema-to-ts'; | ||
|
||
export const projectActivitySchema = { | ||
$id: '#/components/schemas/projectActivitySchema', | ||
type: 'array', | ||
description: | ||
'An array of project activity information. Each item contains a date and the total number of activities for that date.', | ||
items: { | ||
type: 'object', | ||
additionalProperties: false, | ||
required: ['date', 'count'], | ||
properties: { | ||
date: { | ||
type: 'string', | ||
example: '2022-12-14', | ||
description: 'Activity date', | ||
}, | ||
count: { | ||
type: 'integer', | ||
minimum: 0, | ||
description: 'Activity count', | ||
}, | ||
}, | ||
}, | ||
components: { | ||
schemas: {}, | ||
}, | ||
} as const; | ||
|
||
export type ProjectActivitySchema = FromSchema<typeof projectActivitySchema>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { validateSchema } from '../validate'; | ||
import type { ProjectStatusSchema } from './project-status-schema'; | ||
|
||
test('projectStatusSchema', () => { | ||
const data: ProjectStatusSchema = { | ||
activityCountByDate: [ | ||
{ date: '2022-12-14', count: 2 }, | ||
{ date: '2022-12-15', count: 5 }, | ||
], | ||
}; | ||
|
||
expect( | ||
validateSchema('#/components/schemas/projectStatusSchema', data), | ||
).toBeUndefined(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { FromSchema } from 'json-schema-to-ts'; | ||
import { projectActivitySchema } from './project-activity-schema'; | ||
|
||
export const projectStatusSchema = { | ||
$id: '#/components/schemas/projectStatusSchema', | ||
type: 'object', | ||
additionalProperties: false, | ||
required: ['activityCountByDate'], | ||
description: | ||
'Schema representing the overall status of a project, including an array of activity records. Each record in the activity array contains a date and a count, providing a snapshot of the project’s activity level over time.', | ||
properties: { | ||
activityCountByDate: { | ||
$ref: '#/components/schemas/projectActivitySchema', | ||
description: | ||
'Array of activity records with date and count, representing the project’s daily activity statistics.', | ||
}, | ||
}, | ||
components: { | ||
schemas: { | ||
projectActivitySchema, | ||
}, | ||
}, | ||
} as const; | ||
|
||
export type ProjectStatusSchema = FromSchema<typeof projectStatusSchema>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters