-
Notifications
You must be signed in to change notification settings - Fork 304
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2835 from bcameron1231/v4-TeamsAppCatalog
V4 teams app catalog
- Loading branch information
Showing
6 changed files
with
315 additions
and
1 deletion.
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,121 @@ | ||
# @pnp/graph/appcatalog | ||
|
||
The ability to use Teams App Catalog | ||
|
||
## AppCatalog, IAppCatalog | ||
|
||
[![Invokable Banner](https://img.shields.io/badge/Invokable-informational.svg)](../concepts/invokable.md) [![Selective Imports Banner](https://img.shields.io/badge/Selective%20Imports-informational.svg)](../concepts/selective-imports.md) | ||
|
||
## Get Teams Apps in App Catalog | ||
|
||
Using teamsApps() you get the Teams AppCatalog | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
const apps = await graph.appCatalog.teamsApps(); | ||
|
||
``` | ||
## Get Teams Apps by Id | ||
|
||
Using getById() you get the Teams App by Id | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
const apps = await graph.appCatalog.teamsApps.getById('{teams app id}')(); | ||
|
||
``` | ||
## Add a Teams App | ||
|
||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
const appPackage = {...} as Blob; | ||
|
||
//second parameter is "Requires Approval" | ||
const app = await graph.appCatalog.teamsApps.getById('{teams app id}').add(appPackage, false); | ||
|
||
``` | ||
## Update a Teams App | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
const appPackage = {...} as Blob; | ||
|
||
//second parameter is "Requires Approval" | ||
const app = await graph.appCatalog.teamsApps.getById('{teams app id}').update(appPackage, false); | ||
|
||
``` | ||
## Delete a Teams App | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
//delete a Teams App | ||
await graph.appCatalog.teamsApps.getById(app).delete(); | ||
|
||
// delete an un-approved Teams App requires the app definition id. | ||
// sample is just selecting the first app definition. | ||
const appDefinition = (await graph.appCatalog.teamsApps.getById("{teams app id}")()).appDefinitions[0]; | ||
await graph.appCatalog.teamsApps.getById(app).delete(appDefinition); | ||
|
||
``` | ||
## Get Teams App Definitions | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
//get teams app definitions | ||
await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions(); | ||
|
||
``` | ||
## Get Teams App Definitions by Id | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
//get teams app definitions | ||
await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions.getById(`{Teams App Definition Id}`) | ||
|
||
``` | ||
## Get Bot associated with Teams App Definition | ||
|
||
```TypeScript | ||
import { graphfi } from "@pnp/graph"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
|
||
const graph = graphfi(...); | ||
|
||
await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions.getById(`{Teams App Definition Id}`).bot(); | ||
|
||
``` |
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,22 @@ | ||
import { GraphFI } from "../fi.js"; | ||
import { AppCatalog, IAppCatalog} from "./types.js"; | ||
|
||
|
||
export { | ||
AppCatalog, | ||
IAppCatalog, | ||
} from "./types.js"; | ||
|
||
declare module "../fi" { | ||
interface GraphFI { | ||
readonly appCatalog: IAppCatalog; | ||
} | ||
} | ||
|
||
Reflect.defineProperty(GraphFI.prototype, "appCatalog", { | ||
configurable: true, | ||
enumerable: true, | ||
get: function (this: GraphFI) { | ||
return this.create(AppCatalog); | ||
}, | ||
}); |
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,122 @@ | ||
import { | ||
AppCatalogs as IAppCatalogsType, | ||
TeamsApp as ITeamsAppType, | ||
TeamsAppDefinition as ITeamsAppDefinitionType, | ||
TeamworkBot as ITeamworkBot } from "@microsoft/microsoft-graph-types"; | ||
import { _GraphCollection, graphInvokableFactory, _GraphInstance, graphPost, graphDelete, graphGet } from "../graphqueryable.js"; | ||
import { IGetById, defaultPath, getById } from "../decorators.js"; | ||
import { InjectHeaders } from "@pnp/queryable/index.js"; | ||
|
||
/** | ||
* AppCatalogs | ||
*/ | ||
|
||
@defaultPath("appCatalogs") | ||
export class _AppCatalog extends _GraphInstance<IAppCatalogsType> { | ||
/** | ||
* Get teams apps in appCatalog | ||
* | ||
*/ | ||
public get teamsApps(): ITeamsApps { | ||
return TeamsApps(this); | ||
} | ||
|
||
} | ||
export interface IAppCatalog extends _AppCatalog {} | ||
export const AppCatalog = graphInvokableFactory<IAppCatalog>(_AppCatalog); | ||
|
||
/** | ||
* AppDefinition | ||
*/ | ||
export class _AppDefinition extends _GraphInstance<ITeamsAppDefinitionType> { | ||
/** | ||
* Gets bot associated with app | ||
* | ||
*/ | ||
public async bot(): Promise<ITeamworkBot>{ | ||
return graphGet(AppDefinitions(this, "/bot")); | ||
} | ||
} | ||
export interface IAppDefinition extends _AppDefinition { } | ||
export const AppDefinition = graphInvokableFactory<IAppDefinition>(_AppDefinition); | ||
|
||
/** | ||
* AppDefinitions | ||
*/ | ||
|
||
@defaultPath("appDefinitions") | ||
@getById(AppDefinition) | ||
export class _AppDefinitions extends _GraphCollection<ITeamsAppDefinitionType[]> {} | ||
export interface IAppDefinitions extends _AppDefinitions, IGetById<IAppDefinition> {} | ||
export const AppDefinitions = graphInvokableFactory<IAppDefinitions>(_AppDefinitions); | ||
|
||
|
||
/** | ||
* TeamsApp | ||
*/ | ||
export class _TeamsApp extends _GraphInstance<ITeamsAppType> { | ||
/** | ||
* Get app definitions | ||
* | ||
*/ | ||
public get appDefinitions(): IAppDefinitions { | ||
return AppDefinitions(this); | ||
} | ||
|
||
/** | ||
* Deletes a Teams App | ||
* | ||
*/ | ||
public async delete(appDefinitionId?: string): Promise<any> { | ||
// Un-approved apps must be deleted differently. https://learn.microsoft.com/en-us/graph/api/teamsapp-delete?view=graph-rest-1.0&tabs=http#permissions | ||
if(appDefinitionId){ | ||
return graphDelete(AppDefinitions(this,`/${appDefinitionId}`)); | ||
} | ||
return graphDelete(this); | ||
} | ||
|
||
/** | ||
* Updates a Teams App | ||
* | ||
* @param zip zip file of app | ||
* @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. | ||
*/ | ||
public async update(zip: Blob, requiresReview = false): Promise<ITeamsAppType> { | ||
const q = AppDefinitions(this,`?$requiresReview=${requiresReview}`); | ||
q.using(InjectHeaders({ | ||
"Content-Type": "application/zip", | ||
})); | ||
|
||
return graphPost(q, { body: zip }); | ||
} | ||
} | ||
|
||
export interface ITeamsApp extends _TeamsApp{} | ||
export const TeamsApp = graphInvokableFactory<ITeamsApp>(_TeamsApp); | ||
|
||
|
||
/** | ||
* TeamsApps | ||
*/ | ||
|
||
@defaultPath("teamsApps") | ||
@getById(TeamsApp) | ||
export class _TeamsApps extends _GraphCollection<ITeamsAppType[]> { | ||
/** | ||
* Adds a Teams App | ||
* | ||
* @param zip zip file of app | ||
* @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. | ||
* | ||
*/ | ||
public async add(zip: Blob, requiresReview = false): Promise<ITeamsAppType> { | ||
const q = TeamsApp(this, `?requiresReview=${requiresReview}`); | ||
q.using(InjectHeaders({ | ||
"Content-Type": "application/zip", | ||
})); | ||
|
||
return graphPost(q, { body: zip }); | ||
} | ||
} | ||
export interface ITeamsApps extends _TeamsApps, IGetById<ITeamsApp>{} | ||
export const TeamsApps = graphInvokableFactory<ITeamsApps>(_TeamsApps); |
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
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,47 @@ | ||
import { expect } from "chai"; | ||
import "@pnp/graph/teams"; | ||
import "@pnp/graph/appCatalog"; | ||
import { pnpTest } from "../pnp-test.js"; | ||
|
||
describe.only("AppCatalog", function () { | ||
|
||
before(async function () { | ||
|
||
if (!this.pnp.settings.enableWebTests) { | ||
this.skip(); | ||
} | ||
}); | ||
|
||
it("teamsApps", pnpTest("32d84a70-52cb-47c8-8957-cda902c07d85", async function () { | ||
const apps = await this.pnp.graph.appCatalog.teamsApps(); | ||
return expect(apps).to.be.an("array") && expect(apps[0]).to.haveOwnProperty("id"); | ||
})); | ||
|
||
it("teamsApps - getById()", pnpTest("17bfb2cd-8fd3-41d3-a387-2fcf410b7100", async function () { | ||
let passed = false; | ||
const apps = await this.pnp.graph.appCatalog.teamsApps(); | ||
if (apps.length > 0) { | ||
const app = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id)(); | ||
passed = (app.id === apps[0].id); | ||
} | ||
return expect(passed).is.true; | ||
})); | ||
|
||
it("appDefinitions", pnpTest("63c8ef41-067f-4f58-bd78-9b5d8d60b5b4", async function () { | ||
const apps = await this.pnp.graph.appCatalog.teamsApps(); | ||
const appDefinitions = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions(); | ||
return expect(appDefinitions).to.be.an("array") && expect(appDefinitions[0]).to.haveOwnProperty("id"); | ||
})); | ||
|
||
it("appDefinitions - getById()", pnpTest("11dce742-2aeb-4b8e-8967-6f73b7fd55d6", async function () { | ||
let passed = false; | ||
const apps = await this.pnp.graph.appCatalog.teamsApps(); | ||
const appDefinitions = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions(); | ||
|
||
if (apps.length > 0) { | ||
const def = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions.getById(appDefinitions[0].id)(); | ||
passed = (def.id === appDefinitions[0].id); | ||
} | ||
return expect(passed).is.true; | ||
})); | ||
}); |