-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
1,347 additions
and
791 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* This is a generated file, please regenerate and do not modify */ | ||
|
||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
import {WebApi} from '../WebApi/WebApi'; | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "@hso/d365-cli", | ||
"version": "6.0.5", | ||
"version": "6.1.0", | ||
"author": "HSO Innovation <[email protected]> (https://www.hso.com)", | ||
"description": "Dynamics 365 Command Line Interface for TypeScript projects for Dataverse", | ||
"repository": { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import * as shell from 'shelljs'; | ||
import fs from 'fs'; | ||
import {WebresourcesCrmJson} from '../../root/Webresources/CrmJson'; | ||
import {SolutionService} from '../../node/Solution/Solution.service'; | ||
import {CustomApiService} from '../../node/CustomApi/CustomApi.service'; | ||
import {SolutionComponentService} from '../../node/SolutionComponent/SolutionComponent.service'; | ||
import {CustomApiRequestParameterService} from '../../node/CustomApiRequestParameter/CustomApiRequestParameter.service'; | ||
import {CustomApiResponsePropertyService} from '../../node/CustomApiResponseProperty/CustomApiResponseProperty.service'; | ||
import {CustomApiModel} from '../../node/CustomApi/CustomApi.model'; | ||
import {CustomApiRequestParameterModel} from '../../node/CustomApiRequestParameter/CustomApiRequestParameter.model'; | ||
import {CustomApiResponsePropertyModel} from '../../node/CustomApiResponseProperty/CustomApiResponseProperty.model'; | ||
|
||
export class CustomApis { | ||
private readonly bearer: string; | ||
|
||
constructor(bearer: string) { | ||
this.bearer = bearer; | ||
} | ||
|
||
public async generate(): Promise<void> { | ||
console.log(`Generating Custom Apis`); | ||
await this.writeCustomApisFile(); | ||
console.log('Generated Custom Apis'); | ||
} | ||
|
||
private async writeCustomApisFile(): Promise<void> { | ||
console.log(`Generating CustomApis/CustomApis.ts`); | ||
const customApisString = await this.getCustomApisString(); | ||
shell.cp('-r', `${__dirname}/CustomApis`, `src`); | ||
const customApisFilepath = 'src/CustomApis/CustomApis.ts'; | ||
const fileData = String(fs.readFileSync(customApisFilepath)); | ||
shell.ShellString(fileData + customApisString).to(customApisFilepath); | ||
shell.exec(`git add src/CustomApis`); | ||
console.log(`Generated CustomApis/CustomApis.ts`); | ||
} | ||
|
||
// eslint-disable-next-line max-lines-per-function | ||
private async getCustomApisString(): Promise<string> { | ||
let customApiStrings = ''; | ||
const customApis = await this.getCustomApis(); | ||
|
||
for (const customApi of customApis) { | ||
const pascalSchemaName = CustomApis.capitalize(customApi.uniquename); | ||
|
||
const requestParameters = await this.getRequestParameters(customApi); | ||
|
||
customApiStrings += `// eslint-disable-next-line @typescript-eslint/no-empty-interface\n`; | ||
customApiStrings += `interface ${pascalSchemaName}Request {\n`; | ||
for (const requestParameter of requestParameters) { | ||
customApiStrings += ` // ${requestParameter.name}\n`; | ||
customApiStrings += ` // ${requestParameter.description}\n`; | ||
customApiStrings += ` // ${requestParameter.displayname}\n`; | ||
// eslint-disable-next-line max-len | ||
customApiStrings += ` ${requestParameter.uniquename}${requestParameter.isoptional ? '?' : ''}: ${CustomApis.getTypeString(requestParameter.type)};\n\n`; | ||
} | ||
if (requestParameters.length === 0) { | ||
customApiStrings += ` //\n`; | ||
} | ||
customApiStrings += `}\n`; | ||
|
||
const responseProperties = await this.getResponseProperties(customApi); | ||
|
||
customApiStrings += `// eslint-disable-next-line @typescript-eslint/no-empty-interface\n`; | ||
customApiStrings += `interface ${pascalSchemaName}Response {\n`; | ||
for (const responseProperty of responseProperties) { | ||
customApiStrings += ` // ${responseProperty.name}\n`; | ||
customApiStrings += ` // ${responseProperty.description}\n`; | ||
customApiStrings += ` // ${responseProperty.displayname}\n`; | ||
// eslint-disable-next-line max-len | ||
customApiStrings += ` ${responseProperty.uniquename}: ${CustomApis.getTypeString(responseProperty.type)};\n\n`; | ||
} | ||
customApiStrings += `}\n`; | ||
customApiStrings += `// ${customApi.name}\n`; | ||
customApiStrings += `// ${customApi.description}\n`; | ||
customApiStrings += `// ${customApi.displayname}\n`; | ||
customApiStrings += `export const ${pascalSchemaName} = async (request: ${pascalSchemaName}Request): Promise<${pascalSchemaName}Response> => {\n`; | ||
customApiStrings += ` return WebApi.executeAction('${customApi.uniquename}', request);\n`; | ||
customApiStrings += `};\n\n`; | ||
} | ||
if (customApiStrings) { | ||
customApiStrings += '\n'; | ||
} | ||
return customApiStrings; | ||
} | ||
|
||
private async getCustomApis(): Promise<CustomApiModel[]> { | ||
const settings: WebresourcesCrmJson = JSON.parse(fs.readFileSync('./crm.json', 'utf8')); | ||
const {solution_name_generate} = settings.crm; | ||
const solution = await SolutionService.getSolution(solution_name_generate, ['solutionid'], this.bearer); | ||
const solutionComponents = await SolutionComponentService.retrieveMultipleRecords({ | ||
select: ['objectid'], | ||
filters: [{ | ||
conditions: [{ | ||
attribute: '_solutionid_value', | ||
value: solution.solutionid | ||
}] | ||
}, { | ||
type: 'or', | ||
conditions: [{ | ||
attribute: 'componenttype', | ||
value: 10051 // CustomApis | ||
}] | ||
}] | ||
}, this.bearer); | ||
const conditions: Condition[] = []; | ||
for (const solutionComponent of solutionComponents) { | ||
const objectid = solutionComponent.objectid; | ||
conditions.push({ | ||
attribute: 'customapiid', | ||
value: objectid, | ||
}); | ||
} | ||
return CustomApiService.retrieveMultipleRecords({ | ||
select: ['customapiid', 'description', 'displayname', 'name', 'solutionid', 'uniquename'], | ||
filters: [{ | ||
type: 'or', | ||
conditions: conditions | ||
}] | ||
}, this.bearer); | ||
} | ||
|
||
private getRequestParameters(customApi: CustomApiModel): Promise<CustomApiRequestParameterModel[]> { | ||
return CustomApiRequestParameterService.retrieveMultipleRecords({ | ||
select: ['customapirequestparameterid', 'description', 'displayname', 'name', 'solutionid', 'uniquename', 'isoptional', 'type'], | ||
filters: [{ | ||
conditions: [{ | ||
attribute: '_customapiid_value', | ||
value: customApi.customapiid | ||
}] | ||
}] | ||
}, this.bearer); | ||
} | ||
|
||
private getResponseProperties(customApi: CustomApiModel): Promise<CustomApiResponsePropertyModel[]> { | ||
return CustomApiResponsePropertyService.retrieveMultipleRecords({ | ||
select: ['customapiresponsepropertyid', 'description', 'displayname', 'name', 'solutionid', 'uniquename', 'type'], | ||
filters: [{ | ||
conditions: [{ | ||
attribute: '_customapiid_value', | ||
value: customApi.customapiid | ||
}] | ||
}] | ||
}, this.bearer); | ||
} | ||
|
||
private static getTypeString(value: number): string { | ||
if (value === 0) { | ||
return 'boolean'; | ||
} | ||
if (value === 1) { | ||
return 'Date'; | ||
} | ||
if ([2, 6, 7].includes(value)) { | ||
return 'number'; | ||
} | ||
if ([3].includes(value)) { | ||
return 'Model'; | ||
} | ||
if ([4].includes(value)) { | ||
return 'Model[]'; | ||
} | ||
if ([5, 8, 9].includes(value)) { | ||
return 'any'; | ||
} | ||
if ([10, 12].includes(value)) { | ||
return 'string'; | ||
} | ||
if ([11].includes(value)) { | ||
return 'string[]'; | ||
} | ||
} | ||
|
||
private static capitalize(text: string): string { | ||
return text.charAt(0).toUpperCase() + text.slice(1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
|
||
export interface CustomApiModel extends Model { | ||
customapiid?: string; | ||
description?: string; | ||
displayname?: string; | ||
name?: string; | ||
solutionid?: string; | ||
uniquename?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {NodeApi} from '../NodeApi/NodeApi'; | ||
import {CustomApiModel} from './CustomApi.model'; | ||
|
||
export class CustomApiService { | ||
private static entitySetName = 'customapis'; | ||
|
||
public static async retrieveMultipleRecords(multipleSystemQueryOptions: MultipleSystemQueryOptions, bearer: string): Promise<CustomApiModel[]> { | ||
return NodeApi.retrieveMultipleRecords(CustomApiService.entitySetName, multipleSystemQueryOptions, bearer); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/node/CustomApiRequestParameter/CustomApiRequestParameter.model.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
// https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/reference/customapirequestparameter?view=dataverse-latest | ||
export type CustomApiType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; | ||
|
||
export interface CustomApiRequestParameterModel extends Model { | ||
customapirequestparameterid?: string; | ||
description?: string; | ||
displayname?: string; | ||
name?: string; | ||
solutionid?: string; | ||
uniquename?: string; | ||
isoptional?: boolean; | ||
type?: CustomApiType; | ||
} |
10 changes: 10 additions & 0 deletions
10
src/node/CustomApiRequestParameter/CustomApiRequestParameter.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {NodeApi} from '../NodeApi/NodeApi'; | ||
import {CustomApiRequestParameterModel} from './CustomApiRequestParameter.model'; | ||
|
||
export class CustomApiRequestParameterService { | ||
private static entitySetName = 'customapirequestparameters'; | ||
|
||
public static async retrieveMultipleRecords(multipleSystemQueryOptions: MultipleSystemQueryOptions, bearer: string): Promise<CustomApiRequestParameterModel[]> { | ||
return NodeApi.retrieveMultipleRecords(CustomApiRequestParameterService.entitySetName, multipleSystemQueryOptions, bearer); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/node/CustomApiResponseProperty/CustomApiResponseProperty.model.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import {CustomApiType} from '../CustomApiRequestParameter/CustomApiRequestParameter.model'; | ||
|
||
export interface CustomApiResponsePropertyModel extends Model { | ||
customapiresponsepropertyid?: string; | ||
description?: string; | ||
displayname?: string; | ||
name?: string; | ||
solutionid?: string; | ||
uniquename?: string; | ||
type?: CustomApiType; | ||
} |
10 changes: 10 additions & 0 deletions
10
src/node/CustomApiResponseProperty/CustomApiResponseProperty.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {NodeApi} from '../NodeApi/NodeApi'; | ||
import {CustomApiResponsePropertyModel} from './CustomApiResponseProperty.model'; | ||
|
||
export class CustomApiResponsePropertyService { | ||
private static entitySetName = 'customapiresponseproperties'; | ||
|
||
public static async retrieveMultipleRecords(multipleSystemQueryOptions: MultipleSystemQueryOptions, bearer: string): Promise<CustomApiResponsePropertyModel[]> { | ||
return NodeApi.retrieveMultipleRecords(CustomApiResponsePropertyService.entitySetName, multipleSystemQueryOptions, bearer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {MsalRouter} from './MsalRouter'; | ||
import {CustomApis} from '../commands/generators/CustomApis'; | ||
|
||
export class CustomApisRouter extends MsalRouter { | ||
public static generateCustomApis(): Promise<void> { | ||
new CustomApisRouter(); | ||
return null; | ||
} | ||
|
||
protected async onAuthenticated(): Promise<void> { | ||
const customApis = new CustomApis(this.bearer); | ||
await customApis.generate(); | ||
} | ||
} |