Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate to use TokenAuthenticationProvider and fix some samples to certain teamsfx version #978

Merged
merged 1 commit into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading