import ApiClient from './ApiClient'; import { mapLocationACLResponse } from './LocationClient'; import * as L from './types/Location'; import * as R from './types/Resource'; import urls from './urls'; export const mapResourceProfileResponse = ( resourceProfileResponse: R.ResourceProfileResponse, ): R.ResourceProfile => ({ id: resourceProfileResponse.id, email: resourceProfileResponse.email, name: resourceProfileResponse.name, thumbnailUrl: resourceProfileResponse.thumbnail_url, domainId: resourceProfileResponse.domain_id, domainRole: resourceProfileResponse.domain_role, }); export const mapResourceDomainResponse = ( resourceDomainResponse: R.ResourceDomainResponse, ): R.ResourceDomain => ({ id: resourceDomainResponse.id, name: resourceDomainResponse.id, description: resourceDomainResponse.id, adminProfile: mapResourceProfileResponse( resourceDomainResponse.admin_profile, ), }); export const mapResourceACLResponse = ( resourceACLResponse: R.ResourceACLResponse, ): R.ResourceACL => ({ id: resourceACLResponse.id, resourceId: resourceACLResponse.resource_id, profileId: resourceACLResponse.profile_id, grantProfileId: resourceACLResponse.grant_profile_id, grantDomainId: resourceACLResponse.grant_domain_id, grantScope: resourceACLResponse.grant_scope, grantFolderPath: resourceACLResponse.grant_folder_path, readGrant: resourceACLResponse.read_grant, updateGrant: resourceACLResponse.update_grant, deleteGrant: resourceACLResponse.delete_grant, shareGrant: resourceACLResponse.share_grant, fullGrant: resourceACLResponse.full_grant, customAccessGrants: resourceACLResponse.custom_access_grants, updatedAt: resourceACLResponse.updated_at, createdAt: resourceACLResponse.created_at, r: { profile: mapResourceProfileResponse(resourceACLResponse.r.profile), grantProfile: resourceACLResponse.r.grant_profile ? mapResourceProfileResponse(resourceACLResponse.r.grant_profile) : null, }, }); export const mapTagResponse = (tagResponse: R.TagResponse): R.Tag => ({ id: tagResponse.id, key: tagResponse.key, label: tagResponse.label, resourceId: tagResponse.resource_id, type: tagResponse.type, value: tagResponse.value as any, // A typing error is present due to string | Day[] union on this property createdAt: tagResponse.created_at, }); export const mapCreateTag = (tag: R.CreateTag): R.CreateTagResponse => ({ type: tag.type, key: tag.key, label: tag.label, value: tag.value as any, // A typing error is present due to string | Day[] union on this property }); export const mapResourceResponse = ( resourceResponse: R.ResourceResponse, ): R.Resource => ({ id: resourceResponse.id, createdAt: resourceResponse.created_at, updatedAt: resourceResponse.updated_at, deletedAt: resourceResponse.deleted_at, lastActivityAt: resourceResponse.last_activity_at, parentFolderId: resourceResponse.parent_folder_id, profile: mapResourceProfileResponse(resourceResponse.profile), domain: resourceResponse.domain ? mapResourceDomainResponse(resourceResponse.domain) : null, r: { resourceACLs: (resourceResponse.r?.resource_acls || []).map( mapResourceACLResponse, ), tags: (resourceResponse.r?.tags || []).map(mapTagResponse), }, }); export const mapResourceV2Response = ( resourceResponse: R.ResourceV2Response, ): R.ResourceV2 => { return { id: resourceResponse.id, profileId: resourceResponse.profile_id, domainId: resourceResponse.domain_id, parentFolderId: resourceResponse.parent_folder_id, createdAt: resourceResponse.created_at, updatedAt: resourceResponse.updated_at, deletedAt: resourceResponse.deleted_at, r: { // NOTE: resourceResponse.r will not exist for device published content until the // user published after deploying rules and tags. Afterwhich, it's guaranteed to exist. // We need to leave 'r?' for backwards compatibility until all devices have been published // since deploying rules and tags. tags: (resourceResponse.r?.tags || []).map(mapTagResponse), }, }; }; export default class ResourceClient { async createResourceACL(this: ApiClient, acl: R.CreateResourceACL) { const grant_profile_id = 'grantProfileId' in acl ? acl.grantProfileId : undefined; const grant_profile_email = 'grantProfileEmail' in acl ? acl.grantProfileEmail : undefined; const parts = { resource_id: acl.resourceId, grants: acl.grants, }; const body = grant_profile_id ? { ...parts, grant_profile_id, } : { ...parts, grant_profile_email, }; const data = await this.requestProtected< R.CreateResourceACLRequest, R.CreateResourceACLResponse >({ method: 'POST', url: urls.resourceACLs(), body, }); return mapResourceACLResponse(data); } async deleteResourceACL(this: ApiClient, aclId: string) { await this.requestProtected< R.DeleteResourceACLRequest, R.DeleteResourceACLResponse >({ method: 'DELETE', url: urls.resourceACL(aclId), }); } async listResourceACLs( this: ApiClient, resourceId: string, ): Promise { const data = await this.requestProtected< R.ListResourceACLsRequest, R.ListResourceACLsResponse >({ method: 'GET', url: urls.listResourceACLs(resourceId), }); return data.map((acl) => mapResourceACLResponse(acl)); } // V5 methods async createResourceACLV5( this: ApiClient, reqBody: R.CreateResourceACLV5, ): Promise { const data = await this.requestProtected< R.CreateResourceACLV5Request, R.CreateResourceACLV5Response >({ method: 'POST', url: urls.resourceACLV5(reqBody.resourceId), body: { resource_id: reqBody.resourceId, grant_profile_ids: 'grantProfileIds' in reqBody ? reqBody.grantProfileIds : [], grant_domain_id: 'grantDomainId' in reqBody ? reqBody.grantDomainId : '', grants: reqBody.grants, }, }); const acl: L.LocationACLResponse[] = data.acl || []; return acl.map((acl) => mapLocationACLResponse(acl)); } async updateResourceACLV5( this: ApiClient, reqBody: R.UpdateResourceACLV5, ): Promise { const data = await this.requestProtected< R.UpdateResourceACLV5Request, R.UpdateResourceACLV5Response >({ method: 'PUT', url: urls.resourceACLV5(reqBody.resourceId), body: { resource_id: reqBody.resourceId, grant_profile_ids: 'grantProfileIds' in reqBody ? reqBody.grantProfileIds : [], grant_domain_id: 'grantDomainId' in reqBody ? reqBody.grantDomainId : '', grants: reqBody.grants, }, }); const acl: L.LocationACLResponse[] = data.acl || []; return acl.map((acl) => mapLocationACLResponse(acl)); } async deleteResourceACLV5( this: ApiClient, resourceId: string, reqBody: R.DeleteResourceACLV5, ): Promise { await this.requestProtected< R.DeleteResourceACLV5Request, R.DeleteResourceACLV5Response >({ method: 'DELETE', url: urls.resourceACLV5(resourceId), body: { grant_profile_ids: 'grantProfileIds' in reqBody ? reqBody.grantProfileIds : [], grant_domain_id: 'grantDomainId' in reqBody ? reqBody.grantDomainId : '', }, }); } }