-
Notifications
You must be signed in to change notification settings - Fork 188
/
manifestUpdater.ts
137 lines (122 loc) · 4.53 KB
/
manifestUpdater.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
"use strict";
import { OpenAPIV3 } from "openapi-types";
import fs from "fs-extra";
import path from "path";
import { ErrorType, WarningResult } from "./interfaces";
import { Utils } from "./utils";
import { SpecParserError } from "./specParserError";
import { ConstantString } from "./constants";
import {
IComposeExtension,
IMessagingExtensionCommand,
TeamsAppManifest,
} from "@microsoft/teams-manifest";
export class ManifestUpdater {
static async updateManifest(
manifestPath: string,
outputSpecPath: string,
adaptiveCardFolder: string,
spec: OpenAPIV3.Document,
allowMultipleParameters: boolean,
auth?: OpenAPIV3.SecuritySchemeObject,
isMe?: boolean
): Promise<[TeamsAppManifest, WarningResult[]]> {
try {
const originalManifest: TeamsAppManifest = await fs.readJSON(manifestPath);
const updatedPart: any = {};
const [commands, warnings] = await ManifestUpdater.generateCommands(
spec,
adaptiveCardFolder,
manifestPath,
allowMultipleParameters
);
const composeExtension: IComposeExtension = {
composeExtensionType: "apiBased",
apiSpecificationFile: ManifestUpdater.getRelativePath(manifestPath, outputSpecPath),
commands: commands,
};
if (auth) {
if (Utils.isAPIKeyAuth(auth)) {
auth = auth as OpenAPIV3.ApiKeySecurityScheme;
const safeApiSecretRegistrationId = Utils.getSafeRegistrationIdEnvName(
`${auth.name}_${ConstantString.RegistrationIdPostfix}`
);
(composeExtension as any).authorization = {
authType: "apiSecretServiceAuth",
apiSecretServiceAuthConfiguration: {
apiSecretRegistrationId: `\${{${safeApiSecretRegistrationId}}}`,
},
};
} else if (Utils.isBearerTokenAuth(auth)) {
(composeExtension as any).authorization = {
authType: "microsoftEntra",
microsoftEntraConfiguration: {
supportsSingleSignOn: true,
},
};
updatedPart.webApplicationInfo = {
id: "${{AAD_APP_CLIENT_ID}}",
resource: "api://${{DOMAIN}}/${{AAD_APP_CLIENT_ID}}",
};
}
}
updatedPart.description = {
short: spec.info.title.slice(0, ConstantString.ShortDescriptionMaxLens),
full: (spec.info.description ?? originalManifest.description.full)?.slice(
0,
ConstantString.FullDescriptionMaxLens
),
};
updatedPart.composeExtensions = isMe === undefined || isMe === true ? [composeExtension] : [];
const updatedManifest = { ...originalManifest, ...updatedPart };
return [updatedManifest, warnings];
} catch (err) {
throw new SpecParserError((err as Error).toString(), ErrorType.UpdateManifestFailed);
}
}
static async generateCommands(
spec: OpenAPIV3.Document,
adaptiveCardFolder: string,
manifestPath: string,
allowMultipleParameters: boolean
): Promise<[IMessagingExtensionCommand[], WarningResult[]]> {
const paths = spec.paths;
const commands: IMessagingExtensionCommand[] = [];
const warnings: WarningResult[] = [];
if (paths) {
for (const pathUrl in paths) {
const pathItem = paths[pathUrl];
if (pathItem) {
const operations = pathItem;
// Currently only support GET and POST method
for (const method in operations) {
if (method === ConstantString.PostMethod || method === ConstantString.GetMethod) {
const operationItem = operations[method];
if (operationItem) {
const [command, warning] = Utils.parseApiInfo(
operationItem,
allowMultipleParameters
);
const adaptiveCardPath = path.join(adaptiveCardFolder, command.id + ".json");
command.apiResponseRenderingTemplateFile = (await fs.pathExists(adaptiveCardPath))
? ManifestUpdater.getRelativePath(manifestPath, adaptiveCardPath)
: "";
if (warning) {
warnings.push(warning);
}
commands.push(command);
}
}
}
}
}
}
return [commands, warnings];
}
static getRelativePath(from: string, to: string): string {
const relativePath = path.relative(path.dirname(from), to);
return path.normalize(relativePath).replace(/\\/g, "/");
}
}