Skip to content

Commit

Permalink
feat: content type comments (#2023)
Browse files Browse the repository at this point in the history
  • Loading branch information
andipaetzold committed Oct 25, 2023
1 parent 0bd38fc commit f8dec8e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 38 deletions.
47 changes: 32 additions & 15 deletions lib/adapters/REST/endpoints/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,39 @@ const BODY_FORMAT_HEADER = 'x-contentful-comment-body-format'

const getSpaceEnvBaseUrl = (params: GetSpaceEnvironmentParams) =>
`/spaces/${params.spaceId}/environments/${params.environmentId}`
const getEntryBaseUrl = (params: GetEntryParams) =>
`${getSpaceEnvBaseUrl(params)}/entries/${params.entryId}/comments`
const getEntryCommentUrl = (params: GetCommentParams) =>
`${getEntryBaseUrl(params)}/${params.commentId}`
const getEntityCommentUrl = (params: GetCommentParams) =>
`${getEntityBaseUrl(params)}/${params.commentId}`

function getParentPlural(parentEntityType: 'ContentType' | 'Entry' | 'Workflow') {
switch (parentEntityType) {
case 'ContentType':
return 'content_types'
case 'Entry':
return 'entries'
case 'Workflow':
return 'workflows'
}
}

/**
* Comments can be added to either an entry or a workflow. The latter one requires a version
* Comments can be added to a content type, an entry, and a workflow. Workflow comments requires a version
* to be set as part of the URL path. Workflow comments only support `create` (with
* versionized URL) and `getMany` (without version). The API might support more methods
* in the future with new use cases being discovered.
*/
const getEntityBaseUrl = (params: GetEntryParams | GetManyCommentsParams) => {
if ('entryId' in params) {
return getEntryBaseUrl(params)
}
const getEntityBaseUrl = (paramsOrg: GetEntryParams | GetManyCommentsParams) => {
const params: GetManyCommentsParams =
'entryId' in paramsOrg
? {
spaceId: paramsOrg.spaceId,
environmentId: paramsOrg.environmentId,
parentEntityType: 'Entry' as const,
parentEntityId: paramsOrg.entryId,
}
: paramsOrg

const { parentEntityId, parentEntityType } = params
// No need for mapping or switch-case as long as there are only two supported cases
const parentPlural = parentEntityType === 'Workflow' ? 'workflows' : 'entries'
const parentPlural = getParentPlural(parentEntityType)
const versionPath =
'parentEntityVersion' in params ? `/versions/${params.parentEntityVersion}` : ''
return `${getSpaceEnvBaseUrl(params)}/${parentPlural}/${parentEntityId}${versionPath}/comments`
Expand All @@ -54,7 +69,7 @@ export const get: RestEndpoint<'Comment', 'get'> = (
http: AxiosInstance,
params: GetCommentParams & (PlainTextBodyFormat | RichTextBodyFormat)
) =>
raw.get<CommentProps>(http, getEntryCommentUrl(params), {
raw.get<CommentProps>(http, getEntityCommentUrl(params), {
headers:
params.bodyFormat === 'rich-text'
? {
Expand Down Expand Up @@ -102,7 +117,7 @@ export const update: RestEndpoint<'Comment', 'update'> = (
const data: SetOptional<typeof rawData, 'sys'> = copy(rawData)
delete data.sys

return raw.put<CommentProps>(http, getEntryCommentUrl(params), data, {
return raw.put<CommentProps>(http, getEntityCommentUrl(params), data, {
headers: {
'X-Contentful-Version': rawData.sys.version ?? 0,
...(typeof rawData.body !== 'string'
Expand All @@ -119,10 +134,12 @@ export const del: RestEndpoint<'Comment', 'delete'> = (
http: AxiosInstance,
{ version, ...params }: DeleteCommentParams
) => {
return raw.del(http, getEntryCommentUrl(params), { headers: { 'X-Contentful-Version': version } })
return raw.del(http, getEntityCommentUrl(params), {
headers: { 'X-Contentful-Version': version },
})
}

// Add a deprecation notive. But `getAll` may never be removed for app compatibility reasons.
// Add a deprecation notice. But `getAll` may never be removed for app compatibility reasons.
/**
* @deprecated use `getMany` instead.
*/
Expand Down
10 changes: 9 additions & 1 deletion lib/entities/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export type CommentSysProps = Pick<
type: 'Comment'
space: SysLink
environment: SysLink
parentEntity: Link<'Entry'> | LinkWithReference<'Entry'> | VersionedLink<'Workflow'>
parentEntity:
| Link<'ContentType'>
| Link<'Entry'>
| LinkWithReference<'Entry'>
| VersionedLink<'Workflow'>
parent: Link<'Comment'> | null
}

Expand Down Expand Up @@ -80,6 +84,10 @@ export type RichTextCommentProps = Omit<CommentProps, 'body'> & RichTextCommentB
// We keep this type as explicit as possible until we open up the comments entity further
export type GetCommentParentEntityParams = GetSpaceEnvironmentParams &
(
| {
parentEntityType: 'ContentType'
parentEntityId: string
}
| {
parentEntityType: 'Entry'
parentEntityId: string
Expand Down
73 changes: 51 additions & 22 deletions test/integration/comment-integration.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { expect } from 'chai'
import { before, describe, test, after } from 'mocha'
import { initClient, createTestEnvironment, createTestSpace } from '../helpers'
import { initClient, createTestEnvironment, createTestSpace, initPlainClient } from '../helpers'

describe('Comment Api', () => {
let plainClient
let space
let environment
let contentType
let entry
const commentBody = 'JS SDK Comment Integration Test'

before(async () => {
plainClient = initPlainClient()
space = await createTestSpace(initClient(), 'Comment')
environment = await createTestEnvironment(space, 'Comment Testing Environment')
const contentType = await environment.createContentType({ name: 'Content Type' })
contentType = await environment.createContentType({ name: 'Content Type' })
await contentType.publish()
entry = await environment.createEntry(contentType.sys.id, { fields: {} })
})
Expand All @@ -22,33 +25,59 @@ describe('Comment Api', () => {
}
})

test('Get comments', async () => {
const {
sys: { id },
} = await entry.createComment({
body: commentBody,
describe('Entry comment', () => {
test('Get comments', async () => {
const {
sys: { id },
} = await entry.createComment({
body: commentBody,
})

const response = await entry.getComments()
expect(response.items).to.be.an('array')
expect(response.items.map((item) => item.sys.id)).to.include(id)

const comment = await entry.getComment(id)
expect(comment.body).to.eq(commentBody)
await comment.delete()
})

const response = await entry.getComments()
expect(response.items).to.be.an('array')
expect(response.items.map((item) => item.sys.id)).to.include(id)
describe('Create, update, delete comment', async () => {
const comment = await entry.createComment({
body: commentBody,
})

const comment = await entry.getComment(id)
expect(comment.body).to.eq(commentBody)
await comment.delete()
})
expect(comment.body).to.eq(commentBody, 'body is set')
comment.body = 'new body'

test('Create, update, delete comment', async () => {
const comment = await entry.createComment({
body: commentBody,
const updatedBody = await comment.update()
expect(updatedBody.body).to.eq('new body')

await updatedBody.delete()
})
})

expect(comment.body).to.eq(commentBody, 'body is set')
comment.body = 'new body'
describe('Content type comment', () => {
test('Create, get, delete comment', async () => {
const params = {
spaceId: space.sys.id,
environmentId: environment.sys.id,
parentEntityType: 'ContentType',
parentEntityId: contentType.sys.id,
}
const {
sys: { id, version },
} = await plainClient.comment.create(params, { body: commentBody })

const updatedBody = await comment.update()
expect(updatedBody.body).to.eq('new body')
const response = await plainClient.comment.getMany(params)
expect(response.items).to.be.an('array')
expect(response.items.map((item) => item.sys.id)).to.include(id)

await updatedBody.delete()
await plainClient.comment.delete({
...params,
commentId: id,
version,
})
})
})
})

0 comments on commit f8dec8e

Please sign in to comment.