From 197dae390cdb7ede426edc79433ca732a8d70509 Mon Sep 17 00:00:00 2001 From: Zach Hammer Date: Fri, 23 Feb 2024 09:56:54 -0500 Subject: [PATCH] refactor: use application object for awards backend (#30) * set up Awards app class, port put to use that * fix put * move delete into Awards class * create shared "get award by uid" func * move get to class * move create to class * add copyright headers * fix tsc * run prettier --- plugins/awards-backend/src/awards.ts | 76 ++++++++++++++++++++ plugins/awards-backend/src/service/router.ts | 64 +++-------------- plugins/awards-common/src/types/award.ts | 2 + 3 files changed, 89 insertions(+), 53 deletions(-) create mode 100644 plugins/awards-backend/src/awards.ts diff --git a/plugins/awards-backend/src/awards.ts b/plugins/awards-backend/src/awards.ts new file mode 100644 index 0000000..1da7f53 --- /dev/null +++ b/plugins/awards-backend/src/awards.ts @@ -0,0 +1,76 @@ +/* + * Copyright SeatGeek + * Licensed under the terms of the Apache-2.0 license. See LICENSE file in project root for terms. + */ +import { NotFoundError } from '@backstage/errors'; +import { Award, AwardInput } from '@seatgeek/backstage-plugin-awards-common'; +import { Logger } from 'winston'; +import { AwardsStore } from './database/awards'; + +export class Awards { + private readonly db: AwardsStore; + private readonly logger: Logger; + + constructor(db: AwardsStore, logger: Logger) { + this.db = db; + this.logger = logger.child({ class: 'Awards' }); + this.logger.debug('Constructed'); + } + + async get(uid: string): Promise { + return await this.getAwardByUid(uid); + } + + async create(input: AwardInput): Promise { + return await this.db.add( + input.name, + input.description, + input.image, + input.owners, + input.recipients, + ); + } + + async update( + identityRef: string, + uid: string, + input: AwardInput, + ): Promise { + const award = await this.getAwardByUid(uid); + + if (!award.owners.includes(identityRef)) { + throw new Error('Unauthorized to update award'); + } + + const updated = await this.db.update( + uid, + input.name, + input.description, + input.image, + input.owners, + input.recipients, + ); + + return updated; + } + + async delete(identityRef: string, uid: string): Promise { + const award = await this.getAwardByUid(uid); + + if (!award.owners.includes(identityRef)) { + throw new Error('Unauthorized to delete award'); + } + + return await this.db.delete(uid); + } + + private async getAwardByUid(uid: string): Promise { + const res = await this.db.search(uid, '', [], []); + + if (!res || res.length === 0) { + throw new NotFoundError(uid); + } + + return res[0]; + } +} diff --git a/plugins/awards-backend/src/service/router.ts b/plugins/awards-backend/src/service/router.ts index 4f8c25c..c970585 100644 --- a/plugins/awards-backend/src/service/router.ts +++ b/plugins/awards-backend/src/service/router.ts @@ -3,12 +3,12 @@ * Licensed under the terms of the Apache-2.0 license. See LICENSE file in project root for terms. */ import { PluginDatabaseManager, errorHandler } from '@backstage/backend-common'; -import { AuthenticationError, NotFoundError } from '@backstage/errors'; +import { AuthenticationError } from '@backstage/errors'; import { IdentityApi } from '@backstage/plugin-auth-node'; -import { Award } from '@seatgeek/backstage-plugin-awards-common'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; +import { Awards } from '../awards'; import { DatabaseAwardsStore } from '../database/awards'; export interface RouterOptions { @@ -23,6 +23,7 @@ export async function createRouter( const { database, identity, logger } = options; const dbStore = await DatabaseAwardsStore.create({ database: database }); + const awardsApp = new Awards(dbStore, logger); const router = Router(); router.use(express.json()); @@ -76,13 +77,9 @@ export async function createRouter( const uid = request.params.uid; // TODO: validate uuid parameter - const resp = await dbStore.search(uid, '', [], []); - if (!resp) { - throw new NotFoundError(uid); - } - - response.json(resp); + const award = await awardsApp.get(uid); + response.json(award); }); router.put('/:uid', async (request, response) => { @@ -90,30 +87,9 @@ export async function createRouter( const uid = request.params.uid; // TODO: validate uuid parameter + // TODO: validate request.body - const res = await dbStore.search(uid, '', [], []); - - if (!res || res.length === 0) { - throw new NotFoundError(uid); - } - - const award: Award = res[0]; - - if (!award.owners.includes(userRef)) { - throw new Error('Unauthorized to update award'); - } - - logger.debug(request.body); - const { name, description, image, owners, recipients } = request.body; - - const upd = await dbStore.update( - uid, - name, - description, - image, - owners, - recipients, - ); + const upd = await awardsApp.update(userRef, uid, request.body); response.json(upd); }); @@ -124,36 +100,18 @@ export async function createRouter( const uid = request.params.uid; // TODO: validate uuid parameter - const res = await dbStore.search(uid, '', [], []); - - if (!res || res.length === 0) { - throw new NotFoundError(uid); - } + const result = await awardsApp.delete(userRef, uid); - const award: Award = res[0]; - - if (!award.owners.includes(userRef)) { - throw new Error('Unauthorized to delete award'); - } - - response.json(dbStore.delete(uid)); + response.json(result); }); router.post('/', async (request, response) => { // Just to protect the request await getUserRef(identity, request); - const { name, description, image, owners, recipients } = request.body; - - const resp = await dbStore.add( - name, - description, - image, - owners, - recipients, - ); + const award = await awardsApp.create(request.body); - response.json(resp); + response.json(award); }); router.use(errorHandler()); diff --git a/plugins/awards-common/src/types/award.ts b/plugins/awards-common/src/types/award.ts index 0ab92b6..e2a810e 100644 --- a/plugins/awards-common/src/types/award.ts +++ b/plugins/awards-common/src/types/award.ts @@ -11,3 +11,5 @@ export interface Award { owners: string[]; recipients: string[]; } + +export type AwardInput = Omit;