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 Resource Type to contentful-management [DANTE-1832] #2429

Merged
2 changes: 2 additions & 0 deletions lib/adapters/REST/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import * as PreviewApiKey from './preview-api-key'
import * as Release from './release'
import * as ReleaseAction from './release-action'
import * as ResourceProvider from './resource-provider'
import * as ResourceType from './resource-type'
import * as Role from './role'
import * as ScheduledAction from './scheduled-action'
import * as Snapshot from './snapshot'
Expand Down Expand Up @@ -96,6 +97,7 @@ export default {
Release,
ReleaseAction,
ResourceProvider,
ResourceType,
Role,
ScheduledAction,
Snapshot,
Expand Down
48 changes: 48 additions & 0 deletions lib/adapters/REST/endpoints/resource-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { RawAxiosRequestHeaders } from 'axios'
import type { AxiosInstance } from 'contentful-sdk-core'
import * as raw from './raw'
import copy from 'fast-copy'
import type { CollectionProp } from '../../../common-types'
import { type GetResourceTypeParams } from '../../../common-types'
import type { RestEndpoint } from '../types'
import type { ResourceTypeProps, UpsertResourceTypeProps } from '../../../entities/resource-type'

const getBaseUrl = (
params: GetResourceTypeParams | Omit<GetResourceTypeParams, 'resourceTypeId'>
) =>
`/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/resource_provider/resource_types`

const getEntityUrl = (params: GetResourceTypeParams) =>
`${getBaseUrl(params)}/${params.resourceTypeId}`

export const get: RestEndpoint<'ResourceType', 'get'> = (
http: AxiosInstance,
params: GetResourceTypeParams
) => {
return raw.get<ResourceTypeProps>(http, getEntityUrl(params))
}

export const upsert: RestEndpoint<'ResourceType', 'upsert'> = (
http: AxiosInstance,
params: GetResourceTypeParams,
rawData: UpsertResourceTypeProps,
headers?: RawAxiosRequestHeaders
) => {
const data = copy(rawData)

return raw.put<ResourceTypeProps>(http, getEntityUrl(params), data, { headers })
}

export const del: RestEndpoint<'ResourceType', 'delete'> = (
http: AxiosInstance,
params: GetResourceTypeParams
) => {
return raw.del(http, getEntityUrl(params))
}

export const getMany: RestEndpoint<'ResourceType', 'getMany'> = (
http: AxiosInstance,
params: Omit<GetResourceTypeParams, 'resourceTypeId'>
) => {
return raw.get<CollectionProp<ResourceTypeProps>>(http, getBaseUrl(params))
}
22 changes: 22 additions & 0 deletions lib/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ import type {
ResourceProviderProps,
UpsertResourceProviderProps,
} from './entities/resource-provider'
import type { ResourceTypeProps, UpsertResourceTypeProps } from './entities/resource-type'

export interface DefaultElements<TPlainObject extends object = object> {
toPlainObject(): TPlainObject
Expand Down Expand Up @@ -598,6 +599,11 @@ type MRInternal<UA extends boolean> = {
(opts: MROpts<'ResourceProvider', 'upsert', UA>): MRReturn<'ResourceProvider', 'upsert'>
(opts: MROpts<'ResourceProvider', 'delete', UA>): MRReturn<'ResourceProvider', 'delete'>

(opts: MROpts<'ResourceType', 'get', UA>): MRReturn<'ResourceType', 'get'>
(opts: MROpts<'ResourceType', 'upsert', UA>): MRReturn<'ResourceType', 'upsert'>
(opts: MROpts<'ResourceType', 'delete', UA>): MRReturn<'ResourceType', 'delete'>
(opts: MROpts<'ResourceType', 'getMany', UA>): MRReturn<'ResourceType', 'getMany'>

(opts: MROpts<'Role', 'get', UA>): MRReturn<'Role', 'get'>
(opts: MROpts<'Role', 'getMany', UA>): MRReturn<'Role', 'getMany'>
(opts: MROpts<'Role', 'getManyForOrganization', UA>): MRReturn<'Role', 'getManyForOrganization'>
Expand Down Expand Up @@ -780,6 +786,20 @@ export type MRActions = {
}
delete: { params: GetResourceProviderParams; return: any }
}
ResourceType: {
get: { params: GetResourceTypeParams; return: ResourceTypeProps }
getMany: {
params: Omit<GetResourceTypeParams, 'resourceTypeId'>
return: CollectionProp<ResourceTypeProps>
}
upsert: {
params: GetResourceTypeParams
payload: UpsertResourceTypeProps
headers?: RawAxiosRequestHeaders
return: ResourceTypeProps
}
delete: { params: GetResourceTypeParams; return: any }
}
Http: {
get: { params: { url: string; config?: RawAxiosRequestConfig }; return: any }
patch: { params: { url: string; config?: RawAxiosRequestConfig }; payload: any; return: any }
Expand Down Expand Up @@ -2096,6 +2116,8 @@ export type GetUserUIConfigParams = GetUIConfigParams

export type GetResourceProviderParams = GetOrganizationParams & { appDefinitionId: string }

export type GetResourceTypeParams = GetResourceProviderParams & { resourceTypeId: string }

export type QueryParams = { query?: QueryOptions }
export type SpaceQueryParams = { query?: SpaceQueryOptions }
export type PaginationQueryParams = { query?: PaginationQueryOptions }
Expand Down
2 changes: 2 additions & 0 deletions lib/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import * as workflowDefinition from './workflow-definition'
import * as concept from './concept'
import * as conceptScheme from './concept-scheme'
import * as resourceProvider from './resource-provider'
import * as resourceType from './resource-type'

export default {
accessToken,
Expand Down Expand Up @@ -92,6 +93,7 @@ export default {
release,
releaseAction,
resourceProvider,
resourceType,
role,
scheduledAction,
snapshot,
Expand Down
52 changes: 51 additions & 1 deletion lib/entities/resource-provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import type { BasicMetaSysProps, DefaultElements, MakeRequest, SysLink } from '../common-types'
import type {
BasicMetaSysProps,
CollectionProp,
DefaultElements,
MakeRequest,
SysLink,
} from '../common-types'
import { toPlainObject, freezeSys } from 'contentful-sdk-core'
import copy from 'fast-copy'
import enhanceWithMethods from '../enhance-with-methods'
import type { ResourceType, UpsertResourceTypeProps } from './resource-type'
import entities from '.'

export type ResourceProviderProps = {
/**
Expand Down Expand Up @@ -30,12 +38,17 @@ export interface ResourceProvider
DefaultElements<ResourceProviderProps> {
upsert(): Promise<ResourceProvider>
delete(): Promise<void>
upsertResourceType(id: string, data: UpsertResourceTypeProps): Promise<ResourceType>
getResourceType(id: string): Promise<ResourceType>
getResourceTypes(): Promise<CollectionProp<ResourceType>>
}

/**
* @private
*/
function createResourceProviderApi(makeRequest: MakeRequest) {
const { wrapResourceType } = entities.resourceType

return {
/**
* Sends an update to the server with any changes made to the object's properties
Expand Down Expand Up @@ -92,6 +105,43 @@ function createResourceProviderApi(makeRequest: MakeRequest) {
params: getParams(data),
})
},

getResourceType: function getResourceType(id: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a common pattern in this SDK to expose sub resources both in parent resource methods and standalone? Also, do we need docs for these methods?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a separate ticket for updating the docs after we finish this one

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the other question about the standalone vs parent resource in the legacy client, usually in normal cases the parent resource has create and get methods and the standalone resource (child resource) has the update and delete. Let me give you an example to make it clearer: if you want to create a new appDefinition, you do it through the organization resource, so you init the client, getOrganisation, and then through the organisation entity you do the createAppDefition so you end up with the AppDefintion entity that you can update or delete. You cannot add a get on that standalone entity because you can't call that method on the entity itself. however, in the plain client you can do it because basically you call everything related to the standalone entity on the standalone entity.

return makeRequest({
entityType: 'ResourceType',
action: 'get',
params: {
organizationId: this.sys.organization.sys.id,
appDefinitionId: this.sys.appDefinition.sys.id,
resourceTypeId: id,
},
}).then((data) => wrapResourceType(makeRequest, data))
},
upsertResourceType: function upsertResourceType(id: string, data: UpsertResourceTypeProps) {
return makeRequest({
entityType: 'ResourceType',
action: 'upsert',
params: {
organizationId: this.sys.organization.sys.id,
appDefinitionId: this.sys.appDefinition.sys.id,
resourceTypeId: id,
},
payload: data,
}).then((data) => wrapResourceType(makeRequest, data))
},
getResourceTypes: function getResourceTypes() {
return makeRequest({
entityType: 'ResourceType',
action: 'getMany',
params: {
organizationId: this.sys.organization.sys.id,
appDefinitionId: this.sys.appDefinition.sys.id,
},
}).then((data) => {
data.items = data.items.map((item) => wrapResourceType(makeRequest, item))
return data as CollectionProp<ResourceType>
})
},
}
}
/**
Expand Down
140 changes: 140 additions & 0 deletions lib/entities/resource-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import type {
BasicMetaSysProps,
DefaultElements,
GetResourceTypeParams,
MakeRequest,
SysLink,
} from '../common-types'
import { toPlainObject, freezeSys } from 'contentful-sdk-core'
import copy from 'fast-copy'
import enhanceWithMethods from '../enhance-with-methods'

export type ResourceTypeProps = {
/**
* System metadata
*/
sys: Omit<BasicMetaSysProps, 'version'> & {
appDefinition: SysLink
organization: SysLink
resourceProvider: SysLink
}
/**
* Resource Type name
*/
name: string
veu marked this conversation as resolved.
Show resolved Hide resolved
/**
* Resource Type defaultFieldMapping
*/
defaultFieldMapping: {
title: string
subtitle?: string
description?: string
externalUrl?: string
image?: {
url: string
altText?: string
}
badge?: {
label: string
variant: string
}
}
}

export type UpsertResourceTypeProps = Omit<ResourceTypeProps, 'sys'>

export interface ResourceType extends ResourceTypeProps, DefaultElements<ResourceTypeProps> {
upsert(): Promise<ResourceType>
delete(): Promise<void>
}

/**
* @private
*/
function createResourceTypeApi(makeRequest: MakeRequest) {
return {
/**
* Sends an update to the server with any changes made to the object's properties
* @return Object returned from the server with updated changes.
* @example ```javascript
* const contentful = require('contentful-management')
*
* const client = contentful.createClient({
* accessToken: '<content_management_api_key>'
* })
*
* client.getOrganization('<org_id>')
* .then((org) => org.getAppDefinition('<app_def_id>'))
* .then((appDefinition) => appDefinition.getResourceType())
* .then((resourceType) => {
* resourceType.name = '<new_name>'
* return resourceType.upsert()
* })
* .catch(console.error)
* ```
*/
upsert: function upsert() {
const data = this.toPlainObject() as ResourceTypeProps

return makeRequest({
entityType: 'ResourceType',
action: 'upsert',
params: getParams(data),
headers: {},
payload: getUpsertParams(data),
}).then((data) => wrapResourceType(makeRequest, data))
},
/**
* Deletes this object on the server.
* @return Promise for the deletion. It contains no data, but the Promise error case should be handled.
* @example ```javascript
* const contentful = require('contentful-management')
*
* const client = contentful.createClient({
* accessToken: '<content_management_api_key>'
* })
*
* client.getOrganization('<org_id>')
* .then((org) => org.getAppDefinition('<app_def_id>'))
* .then((appDefinition) => appDefinition.getResourceType())
* .then((resourceType) => resourceType.delete())
* .catch(console.error)
* ```
*/
delete: function del() {
const data = this.toPlainObject() as ResourceTypeProps

return makeRequest({
entityType: 'ResourceType',
action: 'delete',
params: getParams(data),
})
},
}
}

const getParams = (data: ResourceTypeProps): GetResourceTypeParams => ({
organizationId: data.sys.organization.sys.id,
appDefinitionId: data.sys.appDefinition.sys.id,
resourceTypeId: data.sys.id,
})

const getUpsertParams = (data: ResourceTypeProps): UpsertResourceTypeProps => ({
name: data.name,
defaultFieldMapping: data.defaultFieldMapping,
})

/**
* @private
* @param makeRequest - function to make requests via an adapter
* @param data - Raw Resource Type data
* @return Wrapped Resource Type data
*/
export function wrapResourceType(makeRequest: MakeRequest, data: ResourceTypeProps): ResourceType {
const resourceType = toPlainObject(copy(data))
const ResourceTypeWithMethods = enhanceWithMethods(
resourceType,
createResourceTypeApi(makeRequest)
)
return freezeSys(ResourceTypeWithMethods)
}
5 changes: 5 additions & 0 deletions lib/export-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,8 @@ export type {
ResourceProviderProps,
UpsertResourceProviderProps,
} from './entities/resource-provider'
export type {
ResourceType,
ResourceTypeProps,
UpsertResourceTypeProps,
} from './entities/resource-type'
2 changes: 2 additions & 0 deletions lib/plain/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ import type { AppAccessTokenPlainClientAPI } from './entities/app-access-token'
import type { ConceptPlainClientAPI } from './entities/concept'
import type { ConceptSchemePlainClientAPI } from './entities/concept-scheme'
import type { ResourceProviderPlainClientAPI } from './entities/resource-provider'
import type { ResourceTypePlainClientAPI } from './entities/resource-type'

export type PlainClientAPI = {
raw: {
Expand Down Expand Up @@ -505,6 +506,7 @@ export type PlainClientAPI = {
appDefinition: AppDefinitionPlainClientAPI
appInstallation: AppInstallationPlainClientAPI
resourceProvider: ResourceProviderPlainClientAPI
resourceType: ResourceTypePlainClientAPI
extension: ExtensionPlainClientAPI
webhook: WebhookPlainClientAPI
snapshot: {
Expand Down
Loading