Skip to content

Commit

Permalink
feat: migrate samples to use TokenAuthenticationProvider and fix some…
Browse files Browse the repository at this point in the history
… samples to certain teamsfx version (#978)
  • Loading branch information
yiqing-zhao committed Aug 7, 2023
1 parent 7d5816a commit 2e420b6
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 172 deletions.
40 changes: 25 additions & 15 deletions graph-connector-app/api/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import "isomorphic-fetch";
import { Context, HttpRequest } from "@azure/functions";
import { Client } from "@microsoft/microsoft-graph-client";
import { AppCredential, AppCredentialAuthConfig, createMicrosoftGraphClientWithCredential } from "@microsoft/teamsfx";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
import { AppCredential, AppCredentialAuthConfig } from "@microsoft/teamsfx";
import config from "../config";

interface Response {
Expand All @@ -15,7 +16,7 @@ const authConfig: AppCredentialAuthConfig = {
clientId: config.clientId,
tenantId: config.tenantId,
clientSecret: config.clientSecret,
}
};

type TeamsfxContext = { [key: string]: any };

Expand All @@ -37,7 +38,7 @@ export default async function run(
const res: Response = {
status: 200,
body: {
connectionAlreadyExists: false
connectionAlreadyExists: false,
},
};

Expand All @@ -58,27 +59,36 @@ export default async function run(

// Create connection
try {
const graphClient: Client = createMicrosoftGraphClientWithCredential(appCredential);
await graphClient.api("/external/connections")
.post({
"id": connectionId,
"name": "Sample connection",
"description": "Sample connection description"
});
// Create an instance of the TokenCredentialAuthenticationProvider by passing the tokenCredential instance and options to the constructor
const authProvider = new TokenCredentialAuthenticationProvider(
appCredential,
{
scopes: ["https://graph.microsoft.com/.default"],
}
);
const graphClient: Client = Client.initWithMiddleware({
authProvider: authProvider,
});
await graphClient.api("/external/connections").post({
id: connectionId,
name: "Sample connection",
description: "Sample connection description",
});
} catch (e) {
if (e?.statusCode === 409) {
res.body.connectionAlreadyExists = true;
}
else {
} else {
context.log.error(e);
let error = "Failed to create a connection for Graph connector: " + e.toString();
let error =
"Failed to create a connection for Graph connector: " + e.toString();
if (e?.statusCode === 401) {
error += " -- Please make sure you have done 'Admin Consent' with 'ExternalConnection.ReadWrite.OwnedBy' and 'ExternalItem.ReadWrite.All' application permissions for your AAD App";
error +=
" -- Please make sure you have done 'Admin Consent' with 'ExternalConnection.ReadWrite.OwnedBy' and 'ExternalItem.ReadWrite.All' application permissions for your AAD App";
}
return {
status: e?.statusCode ?? 500,
body: {
error
error,
},
};
}
Expand Down
70 changes: 44 additions & 26 deletions graph-connector-app/api/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import "isomorphic-fetch";
import { Context, HttpRequest } from "@azure/functions";
import { Client } from "@microsoft/microsoft-graph-client";
import { AppCredential, AppCredentialAuthConfig, createMicrosoftGraphClientWithCredential } from "@microsoft/teamsfx";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
import { AppCredential, AppCredentialAuthConfig } from "@microsoft/teamsfx";
import { readFile } from "fs/promises";
import * as path from "path";
import { parse } from 'csv-parse/sync';
import { parse } from "csv-parse/sync";
import config from "../config";

interface Response {
Expand All @@ -18,7 +19,7 @@ const authConfig: AppCredentialAuthConfig = {
clientId: config.clientId,
tenantId: config.tenantId,
clientSecret: config.clientSecret,
}
};

type TeamsfxContext = { [key: string]: any };

Expand Down Expand Up @@ -59,44 +60,61 @@ export default async function run(

// Ingest data
try {
const csvFileContent = (await readFile(path.join(context.executionContext.functionDirectory, "assets", "ApplianceParts.csv"))).toString();
const csvFileContent = (
await readFile(
path.join(
context.executionContext.functionDirectory,
"assets",
"ApplianceParts.csv"
)
)
).toString();
const records = parse(csvFileContent, {
columns: true,
skip_empty_lines: true
skip_empty_lines: true,
});
// Create an instance of the TokenCredentialAuthenticationProvider by passing the tokenCredential instance and options to the constructor
const authProvider = new TokenCredentialAuthenticationProvider(
appCredential,
{
scopes: ["https://graph.microsoft.com/.default"],
}
);
const graphClient: Client = Client.initWithMiddleware({
authProvider: authProvider,
});
const graphClient: Client = createMicrosoftGraphClientWithCredential(appCredential);
for (const item of records) {
await graphClient.api(`/external/connections/${connectionId}/items/${item.PartNumber}`)
await graphClient
.api(`/external/connections/${connectionId}/items/${item.PartNumber}`)
.put({
"acl": [
acl: [
{
"type": "everyone",
"value": "c5f19b2d-0a77-454a-9b43-abf298c3b34e",
"accessType": "grant"
}
type: "everyone",
value: "c5f19b2d-0a77-454a-9b43-abf298c3b34e",
accessType: "grant",
},
],
"properties": {
"partNumber": Number(item.PartNumber),
"name": item.Name,
"description": item.Description,
"price": Number(item.Price),
"inventory": Number(item.Inventory),
"appliances": item.Appliances.split(";"),
"[email protected]": "Collection(String)"
properties: {
partNumber: Number(item.PartNumber),
name: item.Name,
description: item.Description,
price: Number(item.Price),
inventory: Number(item.Inventory),
appliances: item.Appliances.split(";"),
"[email protected]": "Collection(String)",
},
content: {
type: "text",
value: item.Description,
},
"content": {
"type": "text",
"value": item.Description
}
});
}
} catch (e) {
context.log.error(e);
return {
status: e?.statusCode ?? 500,
body: {
error:
"Failed to ingest items: " + e.toString(),
error: "Failed to ingest items: " + e.toString(),
},
};
}
Expand Down
114 changes: 62 additions & 52 deletions graph-connector-app/api/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import "isomorphic-fetch";
import { Context, HttpRequest } from "@azure/functions";
import { Client, ResponseType } from "@microsoft/microsoft-graph-client";
import { AppCredential, AppCredentialAuthConfig, createMicrosoftGraphClientWithCredential } from "@microsoft/teamsfx";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
import { AppCredential, AppCredentialAuthConfig } from "@microsoft/teamsfx";
import config from "../config";

interface Response {
Expand All @@ -15,7 +16,7 @@ const authConfig: AppCredentialAuthConfig = {
clientId: config.clientId,
tenantId: config.tenantId,
clientSecret: config.clientSecret,
}
};

type TeamsfxContext = { [key: string]: any };

Expand Down Expand Up @@ -56,76 +57,85 @@ export default async function run(

// Register schema
try {
const graphClient: Client = createMicrosoftGraphClientWithCredential(appCredential);
const result = await graphClient.api(`/external/connections/${connectionId}/schema`)
// Create an instance of the TokenCredentialAuthenticationProvider by passing the tokenCredential instance and options to the constructor
const authProvider = new TokenCredentialAuthenticationProvider(
appCredential,
{
scopes: ["https://graph.microsoft.com/.default"],
}
);
const graphClient: Client = Client.initWithMiddleware({
authProvider: authProvider,
});
const result = await graphClient
.api(`/external/connections/${connectionId}/schema`)
.responseType(ResponseType.RAW)
.post({
"baseType": "microsoft.graph.externalItem",
"properties": [
baseType: "microsoft.graph.externalItem",
properties: [
{
"name": "partNumber",
"type": "int64",
"isSearchable": false,
"isRetrievable": true,
"isQueryable": true,
"labels": [],
"aliases": []
name: "partNumber",
type: "int64",
isSearchable: false,
isRetrievable: true,
isQueryable: true,
labels: [],
aliases: [],
},
{
"name": "name",
"type": "string",
"isSearchable": true,
"isRetrievable": true,
"isQueryable": true,
"labels": [],
"aliases": []
name: "name",
type: "string",
isSearchable: true,
isRetrievable: true,
isQueryable: true,
labels: [],
aliases: [],
},
{
"name": "description",
"type": "string",
"isSearchable": true,
"isRetrievable": true,
"isQueryable": false,
"labels": [],
"aliases": []
name: "description",
type: "string",
isSearchable: true,
isRetrievable: true,
isQueryable: false,
labels: [],
aliases: [],
},
{
"name": "price",
"type": "double",
"isSearchable": false,
"isRetrievable": true,
"isQueryable": true,
"labels": [],
"aliases": []
name: "price",
type: "double",
isSearchable: false,
isRetrievable: true,
isQueryable: true,
labels: [],
aliases: [],
},
{
"name": "inventory",
"type": "int64",
"isSearchable": false,
"isRetrievable": true,
"isQueryable": true,
"labels": [],
"aliases": []
name: "inventory",
type: "int64",
isSearchable: false,
isRetrievable: true,
isQueryable: true,
labels: [],
aliases: [],
},
{
"name": "appliances",
"type": "stringCollection",
"isSearchable": true,
"isRetrievable": true,
"isQueryable": true,
"labels": [],
"aliases": []
name: "appliances",
type: "stringCollection",
isSearchable: true,
isRetrievable: true,
isQueryable: true,
labels: [],
aliases: [],
},
]
],
});
res.body.location = result.headers.get('Location');
res.body.location = result.headers.get("Location");
} catch (e) {
context.log.error(e);
return {
status: e?.statusCode ?? 500,
body: {
error:
"Failed to register a schema for connection: " + e.toString(),
error: "Failed to register a schema for connection: " + e.toString(),
},
};
}
Expand Down
19 changes: 14 additions & 5 deletions graph-connector-app/api/status/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import "isomorphic-fetch";
import { Context, HttpRequest } from "@azure/functions";
import { Client } from "@microsoft/microsoft-graph-client";
import { AppCredential, AppCredentialAuthConfig, createMicrosoftGraphClientWithCredential } from "@microsoft/teamsfx";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
import { AppCredential, AppCredentialAuthConfig } from "@microsoft/teamsfx";
import config from "../config";

interface Response {
Expand All @@ -22,7 +23,7 @@ const authConfig: AppCredentialAuthConfig = {
clientId: config.clientId,
tenantId: config.tenantId,
clientSecret: config.clientSecret,
}
};

/**
* @param {Context} context - The Azure Functions context object.
Expand Down Expand Up @@ -59,7 +60,16 @@ export default async function run(

// Query status of schema
try {
let graphClient: Client = createMicrosoftGraphClientWithCredential(appCredential);
// Create an instance of the TokenCredentialAuthenticationProvider by passing the tokenCredential instance and options to the constructor
const authProvider = new TokenCredentialAuthenticationProvider(
appCredential,
{
scopes: ["https://graph.microsoft.com/.default"],
}
);
let graphClient: Client = Client.initWithMiddleware({
authProvider: authProvider,
});
const location = req.query.location;
const result = await graphClient.api(location).get();
res.body.status = result.status;
Expand All @@ -68,8 +78,7 @@ export default async function run(
return {
status: e?.statusCode ?? 500,
body: {
error:
"Failed to check connection schema status: " + e.toString(),
error: "Failed to check connection schema status: " + e.toString(),
},
};
}
Expand Down
Loading

0 comments on commit 2e420b6

Please sign in to comment.