diff --git a/ghost/ghost/src/http/controllers/snippet.dto.ts b/ghost/ghost/src/http/controllers/snippet.dto.ts deleted file mode 100644 index dd079f686f..0000000000 --- a/ghost/ghost/src/http/controllers/snippet.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Snippet} from '../../core/snippets/snippet.entity'; - -export class SnippetDTO { - id: string; - name: string; - lexical?: string|null; - mobiledoc?: string|null; - created_at: Date; - updated_at: Date|null; - - constructor(data: Snippet, options: {formats?: 'mobiledoc'|'lexical'}) { - this.id = data.id.toString(); - this.name = data.name; - - if (options.formats === 'lexical') { - this.lexical = data.lexical || null; - } else { - this.mobiledoc = data.mobiledoc || null; - } - - this.created_at = data.createdAt; - this.updated_at = data.updatedAt || null; - } -} diff --git a/ghost/ghost/src/http/controllers/snippets.controller.test.ts b/ghost/ghost/src/http/controllers/snippets.controller.test.ts deleted file mode 100644 index 9714f7321e..0000000000 --- a/ghost/ghost/src/http/controllers/snippets.controller.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import ObjectId from 'bson-objectid'; -import {Test} from '@nestjs/testing'; -import {Snippet} from '../../core/snippets/snippet.entity'; -import {SnippetsController} from './snippets.controller'; -import {SnippetsService} from '../../core/snippets/snippets.service'; -import {SnippetsRepositoryInMemory} from '../../core/snippets/snippets.repository.inmemory'; -import assert from 'assert/strict'; -import {SnippetsRepository} from '../../core/snippets/snippets.repository.interface'; - -describe('SnippetsController', () => { - let snippetsController: SnippetsController; - let snippetsRepository: SnippetsRepository; - - beforeEach(async () => { - snippetsRepository = new SnippetsRepositoryInMemory(); - const moduleRef = await Test.createTestingModule({ - controllers: [SnippetsController], - providers: [ - { - provide: 'SnippetsRepository', - useValue: snippetsRepository - }, - SnippetsService - ] - }).compile(); - - snippetsController = - moduleRef.get(SnippetsController); - }); - - describe('browse', () => { - it('should return an array of snippets', async () => { - const mockSnippet = new Snippet({ - id: ObjectId(), - deleted: false, - name: 'Test', - mobiledoc: - '{"version":"0.3.1","atoms":[],"cards":[],"markups":[],"sections":[[1,"p",[[0,[],0,"Test"]]]]}', - lexical: undefined, - createdAt: new Date(), - updatedAt: null, - createdBy: ObjectId(), - updatedBy: null - }); - snippetsRepository.save(mockSnippet); - const serviceSnippetResult = { - snippets: [mockSnippet], - pagination: { - page: 1, - limit: 15, - pages: 1, - total: 1 - } - }; - - const response = await snippetsController.browse(); - assert.equal(response.snippets.length, 1); - assert.equal(Object.keys(response.snippets[0]).length, 6); - assert.equal( - response.snippets[0].id, - serviceSnippetResult.snippets[0].id.toString() - ); - assert.equal( - response.snippets[0].name, - serviceSnippetResult.snippets[0].name - ); - assert.equal( - response.snippets[0].mobiledoc, - serviceSnippetResult.snippets[0].mobiledoc - ); - assert.equal(response.snippets[0].lexical, undefined); - assert.equal( - response.snippets[0].created_at, - serviceSnippetResult.snippets[0].createdAt - ); - assert.equal( - response.snippets[0].updated_at, - serviceSnippetResult.snippets[0].updatedAt - ); - }); - }); -}); diff --git a/ghost/ghost/src/http/controllers/snippets.controller.ts b/ghost/ghost/src/http/controllers/snippets.controller.ts deleted file mode 100644 index 6d6ce2b020..0000000000 --- a/ghost/ghost/src/http/controllers/snippets.controller.ts +++ /dev/null @@ -1,161 +0,0 @@ -import {Body, Controller, Delete, Get, HttpCode, Param, Post, Put, Query, UseFilters, UseInterceptors} from '@nestjs/common'; -import {SnippetsService} from '../../core/snippets/snippets.service'; -import {SnippetDTO} from './snippet.dto'; -import {Pagination} from '../../common/types/pagination.type'; -import ObjectID from 'bson-objectid'; -import {now} from '../../common/helpers/date.helper'; -import {LocationHeaderInterceptor} from '../interceptors/location-header.interceptor'; -import {GlobalExceptionFilter} from '../filters/global-exception.filter'; -import {NotFoundError} from '@tryghost/errors'; - -@Controller('snippets') -@UseInterceptors(LocationHeaderInterceptor) -@UseFilters(GlobalExceptionFilter) -export class SnippetsController { - constructor(private readonly service: SnippetsService) {} - - mapBodyToData(body: unknown): {name?: string, description?: string, lexical?: string, mobiledoc?: string} { - if (typeof body !== 'object' || body === null) { - return {}; - } - if (!Reflect.has(body, 'snippets')) { - return {}; - } - - const bodyWithSnippets = body as {snippets: unknown;}; - - if (!Array.isArray(bodyWithSnippets.snippets)) { - return {}; - } - - const firstSnippet = bodyWithSnippets.snippets[0] as unknown; - - if (typeof firstSnippet !== 'object' || firstSnippet === null) { - return {}; - } - - // We use any here because we don't know what the type is, but we are checking that it's a string - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const getString = (obj: object) => (prop: string) => (prop in obj && typeof (obj as any)[prop] === 'string' ? (obj as any)[prop] : undefined); - - const getStringFrom = getString(firstSnippet); - - const data = { - name: getStringFrom('name'), - description: getStringFrom('description'), - lexical: getStringFrom('lexical'), - mobiledoc: getStringFrom('mobiledoc') - }; - - return data; - } - - @Get(':id') - async read( - @Param('id') id: 'string', - @Query('formats') formats?: 'mobiledoc' | 'lexical' - ): Promise<{snippets: [SnippetDTO]}> { - const snippet = await this.service.getOne(ObjectID.createFromHexString(id)); - if (snippet === null) { - throw new NotFoundError({ - context: 'Snippet not found.', - message: 'Resource not found error, cannot read snippet.' - }); - } - return { - snippets: [new SnippetDTO(snippet, {formats})] - }; - } - - @Delete(':id') - @HttpCode(204) - async destroy( - @Param('id') id: 'string' - ) { - const snippet = await this.service.delete(ObjectID.createFromHexString(id)); - if (snippet === null) { - throw new NotFoundError({ - context: 'Resource could not be found.', - message: 'Resource not found error, cannot delete snippet.' - }); - } - return {}; - } - - @Put(':id') - async edit( - @Param('id') id: 'string', - @Body() body: unknown, - @Query('formats') formats?: 'mobiledoc' | 'lexical' - ): Promise<{snippets: [SnippetDTO]}> { - const snippet = await this.service.update(ObjectID.createFromHexString(id), this.mapBodyToData(body)); - if (snippet === null) { - throw new NotFoundError({ - context: 'Snippet not found.', - message: 'Resource not found error, cannot read snippet.' - }); - } - return { - snippets: [new SnippetDTO(snippet, {formats})] - }; - } - - @Post('') - async add( - @Body() body: unknown, - @Query('formats') formats?: 'mobiledoc' | 'lexical' - ): Promise<{snippets: [SnippetDTO]}> { - const snippet = await this.service.create({ - ...this.mapBodyToData(body), - updatedAt: now() - // We cast this as `any` because we're having to pass updatedAt as a hack to replicate broken existing API implementation - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - - return { - snippets: [new SnippetDTO(snippet, {formats})] - }; - } - - @Get('') - async browse( - @Query('formats') formats?: 'mobiledoc' | 'lexical', - @Query('filter') filter?: string, - @Query('page') page: number = 1, - @Query('limit') limit: number | 'all' = 15 - ): Promise<{snippets: SnippetDTO[], meta: {pagination: Pagination;};}> { - let snippets; - let total; - if (limit === 'all') { - snippets = await this.service.getAll({ - filter - }); - total = snippets.length; - } else { - const result = await this.service.getPage({ - filter, - page, - limit - }); - total = result.count; - snippets = result.data; - } - const pages = limit === 'all' ? 0 : Math.ceil(total / limit); - - const snippetDTOs = snippets.map(snippet => new SnippetDTO(snippet, {formats})); - - return { - snippets: snippetDTOs, - meta: { - pagination: { - page, - limit, - total, - pages, - prev: page > 1 ? page - 1 : null, - next: page < pages ? page + 1 : null - } - } - }; - } -} diff --git a/ghost/ghost/src/http/controllers/snippets.dto.test.ts b/ghost/ghost/src/http/controllers/snippets.dto.test.ts deleted file mode 100644 index 5e62279f51..0000000000 --- a/ghost/ghost/src/http/controllers/snippets.dto.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {Snippet} from '../../core/snippets/snippet.entity'; -import ObjectId from 'bson-objectid'; -import assert from 'assert/strict'; -import {SnippetDTO} from './snippet.dto'; - -describe('BrowseSnippetDTO', () => { - it('constructs a BrowseSnippetDTO object from a Snippet object with mobiledoc field', async () => { - const snippet = new Snippet({ - id: ObjectId(), - deleted: false, - name: 'Test', - mobiledoc: '{"version":"0.3.1","atoms":[],"cards":[],"markups":[],"sections":[[1,"p",[[0,[],0,"Test"]]]]}', - lexical: undefined, - createdAt: new Date(), - updatedAt: null, - createdBy: ObjectId(), - updatedBy: null - }); - - const browseSnippetDTO = new SnippetDTO(snippet, {formats: 'mobiledoc'}); - - assert(browseSnippetDTO, 'BrowseSnippetDTO object is not null'); - assert.equal(browseSnippetDTO.id, snippet.id.toString()); - assert.equal(browseSnippetDTO.name, snippet.name); - assert.equal(browseSnippetDTO.mobiledoc, snippet.mobiledoc); - assert.equal(browseSnippetDTO.lexical, undefined); - }); - - it('constructs a BrowseSnippetDTO object from a Snippet object with lexical field', async () => { - const snippet = new Snippet({ - deleted: false, - id: ObjectId(), - name: 'Test', - mobiledoc: undefined, - lexical: `{"root":{"children":[{"type":"html","version":1,"html":"

hey!

"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`, - createdAt: new Date(), - updatedAt: null, - createdBy: ObjectId(), - updatedBy: null - }); - - const browseSnippetDTO = new SnippetDTO(snippet, {formats: 'lexical'}); - - assert(browseSnippetDTO, 'BrowseSnippetDTO object is not null'); - assert.equal(browseSnippetDTO.id, snippet.id.toString()); - assert.equal(browseSnippetDTO.name, snippet.name); - assert.equal(browseSnippetDTO.mobiledoc, undefined); - assert.equal(browseSnippetDTO.lexical, snippet.lexical); - }); -});