Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add content type comments #2023

Merged
merged 5 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
})
})
})
})