/*! * @license * Copyright Squiz Australia Pty Ltd. All Rights Reserved. */ import { inject } from 'inversify'; import { produce } from 'immer'; import { JobContextRepository } from '../../repository'; import { provideSingleton } from '../../singletonProvider'; import { encodeTokenString, getFormattedResponse, PaginationFormattedResponse, PaginationInfo, PaginationKey, PaginationResponse, PaginationService, } from '../../core/pagination'; import { CreateJobContextRequest, JobContext, JobContextDto, UpdateJobContextRequest } from '../../model/JobContext'; import { CreateLog, Logger } from '@squiz/optimization-logger'; import { InjectTokens } from '../../constants/InjectTokens'; @provideSingleton(JobContextService) export class JobContextService { constructor( @inject(JobContextRepository) protected jobContextRepository: JobContextRepository, @inject(PaginationService) protected paginationService: PaginationService, @inject(InjectTokens.Logger) protected logger: Logger, ) {} public async createJobContext(input: CreateJobContextRequest): Promise { const context = await this.jobContextRepository.create(input); this.logContextAction(`Created job context ${context.contextName}`, context); return context; } public async updateJobContext(contextName: string, input: UpdateJobContextRequest): Promise { const context = await this.jobContextRepository.update({ contextName }, input); this.logContextAction(`Updated job context ${context.contextName}`, context); return context; } public async listAllJobContexts(): Promise> { return this.jobContextRepository.list(); } public async listJobContexts(paginationInfo: PaginationInfo): Promise> { const { links, data } = await this.listContextsUpToLimit(paginationInfo); return getFormattedResponse({ links, data }); } private async listContextsUpToLimit(paginationInfo: PaginationInfo): Promise> { const { limit, token } = paginationInfo; let currentToken = token; const contexts: Array = []; do { const newRequestData = { ...paginationInfo, token: currentToken, }; const { items, lastEvaluatedKey } = await this.jobContextRepository.getContexts(newRequestData); contexts.push(...items); currentToken = lastEvaluatedKey ? encodeTokenString(lastEvaluatedKey as unknown as PaginationKey) : null; } while (currentToken && contexts.length < limit); return this.paginationService.addPaginationLinksToResponse(contexts, paginationInfo, currentToken, (context) => this.jobContextRepository.convertToDynamoDbItem(context), ); } public async findJobContext(contextName: string): Promise { return this.jobContextRepository.findOne({ contextName }); } public async deleteJobContext(context: JobContext): Promise { await this.jobContextRepository.delete({ contextName: context.contextName }); this.logContextAction(`Deleted job context ${context.contextName}`, context); } private logContextAction(message: string, context: JobContext) { const { type: _, ...maskedContext } = produce(context, (draft) => { for (const key in draft.environment) { draft.environment[key] = '*redacted*'; } return draft; }); const log = CreateLog.create() .attachMetadata({ details: { context: maskedContext, }, }) .processable() .remote() .create(); this.logger.audit(...log(message)); } }