Skip to content

Commit

Permalink
feat: add resource methods [DANTE-1405] (#2436)
Browse files Browse the repository at this point in the history
* feat: add Resource Type to contentful-management [DANTE-1832]

* feat: add tests

* feat: add getMany and orgId to ResourceType APIs

* fix: unit test

* fix: remove resource type id in test

* feat: update comments, add more tests

* feat: add resource methods

* fix: unit tests

* fix: lint

* fix: improve the mocked data in functions for a better integration test

* feat: export the resource related types

* fix: wait 1s after deletion

* fix: remove type id from getMany

* fix: make the query params optional for resources and resourceTypes

---------

Co-authored-by: Maya <maya.karabulastysiak@gmail.com>
  • Loading branch information
Cyberxon and mayakarabula authored Sep 18, 2024
1 parent 2b67208 commit dd4e663
Show file tree
Hide file tree
Showing 21 changed files with 721 additions and 10 deletions.
2 changes: 2 additions & 0 deletions lib/adapters/REST/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import * as AccessToken from './access-token'
import * as PreviewApiKey from './preview-api-key'
import * as Release from './release'
import * as ReleaseAction from './release-action'
import * as Resource from './resource'
import * as ResourceProvider from './resource-provider'
import * as ResourceType from './resource-type'
import * as Role from './role'
Expand Down Expand Up @@ -96,6 +97,7 @@ export default {
PreviewApiKey,
Release,
ReleaseAction,
Resource,
ResourceProvider,
ResourceType,
Role,
Expand Down
29 changes: 26 additions & 3 deletions lib/adapters/REST/endpoints/resource-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ 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 {
BasicCursorPaginationOptions,
CursorPaginatedCollectionProp,
GetResourceTypeParams,
CollectionProp,
GetSpaceEnvironmentParams,
} from '../../../common-types'
import type { RestEndpoint } from '../types'
import type { ResourceTypeProps, UpsertResourceTypeProps } from '../../../entities/resource-type'
import type {
ResourceTypeProps,
SpaceEnvResourceTypeProps,
UpsertResourceTypeProps,
} from '../../../entities/resource-type'

const getBaseUrl = (
params: GetResourceTypeParams | Omit<GetResourceTypeParams, 'resourceTypeId'>
Expand All @@ -15,6 +24,10 @@ const getBaseUrl = (
const getEntityUrl = (params: GetResourceTypeParams) =>
`${getBaseUrl(params)}/${params.resourceTypeId}`

const getSpaceEnvUrl = (
params: GetSpaceEnvironmentParams & { query?: BasicCursorPaginationOptions }
) => `/spaces/${params.spaceId}/environments/${params.environmentId}/resource_types`

export const get: RestEndpoint<'ResourceType', 'get'> = (
http: AxiosInstance,
params: GetResourceTypeParams
Expand Down Expand Up @@ -46,3 +59,13 @@ export const getMany: RestEndpoint<'ResourceType', 'getMany'> = (
) => {
return raw.get<CollectionProp<ResourceTypeProps>>(http, getBaseUrl(params))
}

export const getForEnvironment: RestEndpoint<'ResourceType', 'getForEnvironment'> = (
http: AxiosInstance,
params: GetSpaceEnvironmentParams & { query?: BasicCursorPaginationOptions }
) => {
return raw.get<CursorPaginatedCollectionProp<SpaceEnvResourceTypeProps>>(
http,
getSpaceEnvUrl(params)
)
}
16 changes: 16 additions & 0 deletions lib/adapters/REST/endpoints/resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { CursorPaginatedCollectionProp, GetResourceParams } from '../../../common-types'
import type { RestEndpoint } from '../types'
import type { AxiosInstance } from 'contentful-sdk-core'
import * as raw from './raw'
import type { ResourceProps, ResourceQueryOptions } from '../../../entities/resource'

const getBaseUrl = (params: GetResourceParams) =>
`/spaces/${params.spaceId}/environments/${params.environmentId}/resource_types/${params.resourceTypeId}/resources`

export const getMany: RestEndpoint<'Resource', 'getMany'> = (
http: AxiosInstance,
params: GetResourceParams & { query?: ResourceQueryOptions }
) =>
raw.get<CursorPaginatedCollectionProp<ResourceProps>>(http, getBaseUrl(params), {
params: params.query,
})
26 changes: 24 additions & 2 deletions lib/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ import type {
ResourceProviderProps,
UpsertResourceProviderProps,
} from './entities/resource-provider'
import type { ResourceTypeProps, UpsertResourceTypeProps } from './entities/resource-type'
import type {
ResourceTypeProps,
SpaceEnvResourceTypeProps,
UpsertResourceTypeProps,
} from './entities/resource-type'
import type { ResourceProps, ResourceQueryOptions } from './entities/resource'

export interface DefaultElements<TPlainObject extends object = object> {
toPlainObject(): TPlainObject
Expand Down Expand Up @@ -594,14 +599,18 @@ type MRInternal<UA extends boolean> = {
'ReleaseAction',
'queryForRelease'
>

(opts: MROpts<'Resource', 'getMany', UA>): MRReturn<'Resource', 'getMany'>
(opts: MROpts<'ResourceProvider', 'get', UA>): MRReturn<'ResourceProvider', 'get'>
(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', 'getForEnvironment', UA>): MRReturn<
'ResourceType',
'getForEnvironment'
>
(opts: MROpts<'ResourceType', 'getMany', UA>): MRReturn<'ResourceType', 'getMany'>

(opts: MROpts<'Role', 'get', UA>): MRReturn<'Role', 'get'>
Expand Down Expand Up @@ -776,6 +785,13 @@ export interface Adapter {
* @private
*/
export type MRActions = {
Resource: {
getMany: {
params: GetResourceParams & { query?: ResourceQueryOptions }
headers?: RawAxiosRequestHeaders
return: CursorPaginatedCollectionProp<ResourceProps>
}
}
ResourceProvider: {
get: { params: GetResourceProviderParams; return: ResourceProviderProps }
upsert: {
Expand All @@ -799,6 +815,10 @@ export type MRActions = {
return: ResourceTypeProps
}
delete: { params: GetResourceTypeParams; return: any }
getForEnvironment: {
params: GetSpaceEnvironmentParams & { query?: BasicCursorPaginationOptions }
return: CursorPaginatedCollectionProp<SpaceEnvResourceTypeProps>
}
}
Http: {
get: { params: { url: string; config?: RawAxiosRequestConfig }; return: any }
Expand Down Expand Up @@ -2118,6 +2138,8 @@ export type GetResourceProviderParams = GetOrganizationParams & { appDefinitionI

export type GetResourceTypeParams = GetResourceProviderParams & { resourceTypeId: string }

export type GetResourceParams = GetSpaceEnvironmentParams & { resourceTypeId: string }

export type QueryParams = { query?: QueryOptions }
export type SpaceQueryParams = { query?: SpaceQueryOptions }
export type PaginationQueryParams = { query?: PaginationQueryOptions }
Expand Down
79 changes: 79 additions & 0 deletions lib/create-environment-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { wrapUIConfig } from './entities/ui-config'
import { wrapUserUIConfig } from './entities/user-ui-config'
import { wrapEnvironmentTemplateInstallationCollection } from './entities/environment-template-installation'
import type { CreateAppAccessTokenProps } from './entities/app-access-token'
import type { ResourceQueryOptions } from './entities/resource'

/**
* @private
Expand Down Expand Up @@ -75,6 +76,8 @@ export default function createEnvironmentApi(makeRequest: MakeRequest) {
const { wrapAppActionCall } = entities.appActionCall
const { wrapBulkAction } = entities.bulkAction
const { wrapAppAccessToken } = entities.appAccessToken
const { wrapResourceTypesForEnvironmentCollection } = entities.resourceType
const { wrapResourceCollection } = entities.resource

return {
/**
Expand Down Expand Up @@ -2280,5 +2283,81 @@ export default function createEnvironmentApi(makeRequest: MakeRequest) {
},
}).then((data) => wrapEnvironmentTemplateInstallationCollection(makeRequest, data))
},

/**
* Gets a collection of all resource types based on native external references app installations in the environment
* @param query - BasicCursorPaginationOptions
* @return Promise for a collection of ResourceTypes
* ```javascript
* const contentful = require('contentful-management')
*
* const client = contentful.createClient({
* accessToken: '<content_management_api_key>'
* })
*
* client.getSpace('<space_id>')
* .then((space) => space.getEnvironment('<environment_id>'))
* .then((environment) => environment.getResourceTypes({limit: 10}))
* .then((installations) => console.log(installations.items))
* .catch(console.error)
* ```
*/
async getResourceTypes(query?: BasicCursorPaginationOptions) {
const raw: EnvironmentProps = this.toPlainObject()

return makeRequest({
entityType: 'ResourceType',
action: 'getForEnvironment',
params: {
query,
spaceId: raw.sys.space.sys.id,
environmentId: raw.sys.id,
},
}).then((data) => wrapResourceTypesForEnvironmentCollection(makeRequest, data))
},

/**
* Gets a collection of all resources for a given resource type based on native external references app installations in the environment
* @param resourceTypeId - Id of the resourceType to get its resources
* @param query - Either LookupQuery options with 'sys.urn[in]' param or a Search query with 'query' param, in both cases you can add pagination options
* @return Promise for a collection of Resources for a given resourceTypeId
* ```javascript
* const contentful = require('contentful-management')
*
* const client = contentful.createClient({
* accessToken: '<content_management_api_key>'
* })
*
* // Search Query
* client.getSpace('<space_id>')
* .then((space) => space.getEnvironment('<environment_id>'))
* // <search_query> is a string you want to search for in the external resources
* .then((environment) => environment.getResourcesForResourceType('<resource_type_id>', {query: '<search_query>', limit: 10}))
* .then((installations) => console.log(installations.items))
* .catch(console.error)
*
* // Lookup query
*
* client.getSpace('<space_id>')
* .then((space) => space.getEnvironment('<environment_id>'))
* .then((environment) => environment.getResourcesForResourceType('<resource_type_id>', {'sys.urn[in]': '<resource_urn1>,<resource_urn2>', limit: 10}))
* .then((installations) => console.log(installations.items))
* .catch(console.error)
* ```
*/
async getResourcesForResourceType(resourceTypeId: string, query?: ResourceQueryOptions) {
const raw: EnvironmentProps = this.toPlainObject()

return makeRequest({
entityType: 'Resource',
action: 'getMany',
params: {
query,
spaceId: raw.sys.space.sys.id,
environmentId: raw.sys.id,
resourceTypeId,
},
}).then((data) => wrapResourceCollection(makeRequest, data))
},
}
}
2 changes: 2 additions & 0 deletions lib/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import * as concept from './concept'
import * as conceptScheme from './concept-scheme'
import * as resourceProvider from './resource-provider'
import * as resourceType from './resource-type'
import * as resource from './resource'

export default {
accessToken,
Expand Down Expand Up @@ -94,6 +95,7 @@ export default {
releaseAction,
resourceProvider,
resourceType,
resource,
role,
scheduledAction,
snapshot,
Expand Down
1 change: 1 addition & 0 deletions lib/entities/resource-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ function createResourceProviderApi(makeRequest: MakeRequest) {
appDefinitionId: this.sys.appDefinition.sys.id,
resourceTypeId: id,
},
headers: {},
payload: data,
}).then((data) => wrapResourceType(makeRequest, data))
},
Expand Down
37 changes: 36 additions & 1 deletion lib/entities/resource-type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {
BasicMetaSysProps,
CursorPaginatedCollectionProp,
DefaultElements,
GetResourceTypeParams,
MakeRequest,
Expand All @@ -8,15 +9,16 @@ import type {
import { toPlainObject, freezeSys } from 'contentful-sdk-core'
import copy from 'fast-copy'
import enhanceWithMethods from '../enhance-with-methods'
import { wrapCursorPaginatedCollection } from '../common-utils'

export type ResourceTypeProps = {
/**
* System metadata
*/
sys: Omit<BasicMetaSysProps, 'version'> & {
appDefinition: SysLink
organization: SysLink
resourceProvider: SysLink
organization: SysLink
}
/**
* Resource Type name
Expand All @@ -40,6 +42,24 @@ export type ResourceTypeProps = {
}
}
}
const publicResourceTypeFields = ['name'] as const

type OptionalSysFields =
| 'createdAt'
| 'createdBy'
| 'updatedAt'
| 'updatedBy'
| 'appDefinition'
| 'organization'

export type SpaceEnvResourceTypeProps = Pick<
ResourceTypeProps,
typeof publicResourceTypeFields[number]
> & {
// we mark timestamps and users as optional to include system types like `Contentful:Entry` into the public response
sys: Partial<Pick<ResourceTypeProps['sys'], OptionalSysFields>> &
Omit<ResourceTypeProps['sys'], OptionalSysFields>
}

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

Expand Down Expand Up @@ -138,3 +158,18 @@ export function wrapResourceType(makeRequest: MakeRequest, data: ResourceTypePro
)
return freezeSys(ResourceTypeWithMethods)
}

export function wrapResourceTypeforEnvironment(
makeRequest: MakeRequest,
data: SpaceEnvResourceTypeProps
): SpaceEnvResourceTypeProps {
const resourceType = toPlainObject(data)
return freezeSys(resourceType)
}

export const wrapResourceTypesForEnvironmentCollection: (
makeRequest: MakeRequest,
data: CursorPaginatedCollectionProp<SpaceEnvResourceTypeProps>
) => CursorPaginatedCollectionProp<SpaceEnvResourceTypeProps> = wrapCursorPaginatedCollection(
wrapResourceTypeforEnvironment
)
50 changes: 50 additions & 0 deletions lib/entities/resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type {
BasicCursorPaginationOptions,
CursorPaginatedCollectionProp,
MakeRequest,
SysLink,
} from '../common-types'
import { wrapCursorPaginatedCollection } from '../common-utils'
import { freezeSys, toPlainObject } from 'contentful-sdk-core'

export type ResourceQueryOptions = LookupQueryOptions | SearchQueryOptions

type LookupQueryOptions = {
'sys.urn[in]': string
} & BasicCursorPaginationOptions

type SearchQueryOptions = {
query: string
} & BasicCursorPaginationOptions

export type ResourceProps = {
sys: {
type: 'Resource'
urn: string
resourceType: SysLink
resourceProvider: SysLink
appDefinition: SysLink
}
fields: {
title: string
subtitle?: string
description?: string
externalUrl?: string
image?: {
url: string
altText?: string
}
badge?: {
label: string
variant: 'primary' | 'negative' | 'positive' | 'warning' | 'secondary'
}
}
}
export function wrapResource(makeRequest: MakeRequest, data: ResourceProps) {
const resource = toPlainObject(data)
return freezeSys(resource)
}
export const wrapResourceCollection: (
makeRequest: MakeRequest,
data: CursorPaginatedCollectionProp<ResourceProps>
) => CursorPaginatedCollectionProp<ResourceProps> = wrapCursorPaginatedCollection(wrapResource)
2 changes: 2 additions & 0 deletions lib/export-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,7 @@ export type {
export type {
ResourceType,
ResourceTypeProps,
SpaceEnvResourceTypeProps,
UpsertResourceTypeProps,
} from './entities/resource-type'
export type { ResourceProps, ResourceQueryOptions } from './entities/resource'
Loading

0 comments on commit dd4e663

Please sign in to comment.