diff --git a/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.schema b/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.schema new file mode 100644 index 0000000000..39d3fedb45 --- /dev/null +++ b/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.schema @@ -0,0 +1,38 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema", + "$role": "implements(Microsoft.IDialog)", + "title": "Get meeting information", + "description": "Get teams meeting information.", + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Optional id for the dialog" + }, + "property": { + "$ref": "schema:#/definitions/stringExpression", + "title": "Property", + "description": "Property (named location to store information).", + "examples": [ + "dialog.meetingInfo" + ] + }, + "meetingId": { + "$ref": "schema:#/definitions/stringExpression", + "title": "Meeting id", + "description": "Meeting Id or expression to a meetingId to use to get the meeting information. Default value is the current turn.activity.channelData.meeting.id.", + "examples": [ + "=turn.activity.channelData.meeting.id" + ] + }, + "disabled": { + "$ref": "schema:#/definitions/booleanExpression", + "title": "Disabled", + "description": "Optional condition which if true will disable this action.", + "examples": [ + "=user.age > 3" + ] + } + } +} \ No newline at end of file diff --git a/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.uischema b/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.uischema new file mode 100644 index 0000000000..9f79a1de99 --- /dev/null +++ b/packages/Teams/js/schemas/Actions/Teams.GetMeetingInfo.uischema @@ -0,0 +1,6 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema", + "menu": { + "submenu": ["Microsoft Teams", "Get Teams Info"] + } +} \ No newline at end of file diff --git a/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.schema b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.schema new file mode 100644 index 0000000000..e339419fb0 --- /dev/null +++ b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.schema @@ -0,0 +1,9 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema", + "$role": [ "implements(Microsoft.ITrigger)", "extends(Microsoft.OnCondition)" ], + "title": "On meeting end", + "description": "Actions triggered when a Teams Meeting is ended", + "type": "object", + "required": [ + ] +} diff --git a/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.uischema b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.uischema new file mode 100644 index 0000000000..98cfcc870a --- /dev/null +++ b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingEnd.uischema @@ -0,0 +1,7 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema", + "trigger": { + "submenu": "Microsoft Teams", + "label": "On meeting end" + } +} diff --git a/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.schema b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.schema new file mode 100644 index 0000000000..e30ddfff41 --- /dev/null +++ b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.schema @@ -0,0 +1,9 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema", + "$role": [ "implements(Microsoft.ITrigger)", "extends(Microsoft.OnCondition)" ], + "title": "On meeting start", + "description": "Actions triggered when a Teams Meeting is started", + "type": "object", + "required": [ + ] +} diff --git a/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.uischema b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.uischema new file mode 100644 index 0000000000..440af4b889 --- /dev/null +++ b/packages/Teams/js/schemas/TriggerConditions/Teams.OnMeetingStart.uischema @@ -0,0 +1,7 @@ +{ + "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema", + "trigger": { + "submenu": "Microsoft Teams", + "label": "On meeting start" + } +} diff --git a/packages/Teams/js/src/actions/getMeetingInfo.ts b/packages/Teams/js/src/actions/getMeetingInfo.ts new file mode 100644 index 0000000000..45a40da2af --- /dev/null +++ b/packages/Teams/js/src/actions/getMeetingInfo.ts @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + BoolExpression, + BoolExpressionConverter, + Expression, + StringExpression, + StringExpressionConverter, +} from 'adaptive-expressions'; +import { Channels, TeamsInfo } from 'botbuilder'; +import { + Converter, + ConverterFactory, + Dialog, + DialogConfiguration, + DialogContext, + DialogTurnResult, +} from 'botbuilder-dialogs'; +import { getValue } from './actionHelpers'; + +export interface GetMeetingInfoConfiguration + extends DialogConfiguration { + disabled?: boolean | string | BoolExpression; + property?: string | Expression | StringExpression; + meetingId?: string | Expression | StringExpression; +} + +/** + * Calls `TeamsInfo.getMeetingInfo` and sets the result to a memory property. + */ +export class GetMeetingInfo + extends Dialog + implements GetMeetingInfoConfiguration { + /** + * Class identifier. + */ + static $kind = 'Teams.GetMeetingInfo'; + + /** + * Gets or sets an optional expression which if is true will disable this action. + * + * @example + * "user.age > 18". + */ + public disabled?: BoolExpression; + + /** + * Gets or sets property path to put the value in. + */ + public property?: StringExpression; + + /** + * Gets or sets the expression to get the value to use for meeting id. + * + * @default + * =turn.activity.channelData.meeting.id + */ + public meetingId = new StringExpression( + '=turn.activity.channelData.meeting.id' + ); + + public getConverter( + property: keyof GetMeetingInfoConfiguration + ): Converter | ConverterFactory { + switch (property) { + case 'disabled': + return new BoolExpressionConverter(); + case 'property': + case 'meetingId': + return new StringExpressionConverter(); + default: + return super.getConverter(property); + } + } + + /** + * Called when the dialog is started and pushed onto the dialog stack. + * + * @param {DialogContext} dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation. + * @param {object} _options Optional, initial information to pass to the dialog. + * @returns {Promise} A promise representing the asynchronous operation. + */ + public async beginDialog( + dc: DialogContext, + _options?: Record + ): Promise { + if (this.disabled?.getValue(dc.state)) { + return dc.endDialog(); + } + + if (dc.context.activity.channelId !== Channels.Msteams) { + throw new Error( + `${GetMeetingInfo.$kind} works only on the Teams channel.` + ); + } + + const meetingId = getValue(dc, this.meetingId); + + const result = await TeamsInfo.getMeetingInfo( + dc.context, + meetingId + ); + + if (this.property != null) { + dc.state.setValue(this.property.getValue(dc.state), result); + } + + return dc.endDialog(result); + } + + /** + * Builds the compute Id for the dialog. + * + * @returns {string} A string representing the compute Id. + */ + protected onComputeId(): string { + return `GetMeetingInfo[\ + ${this.meetingId ?? ''},\ + ${this.property?.toString() ?? ''}\ + ]`; + } +} diff --git a/packages/Teams/js/src/actions/index.ts b/packages/Teams/js/src/actions/index.ts index 30897cccdb..c131adaa4a 100644 --- a/packages/Teams/js/src/actions/index.ts +++ b/packages/Teams/js/src/actions/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +export * from './getMeetingInfo'; export * from './getMeetingParticipant'; export * from './getMember'; export * from './getPagedMembers'; diff --git a/packages/Teams/js/src/adaptiveTeamsBotComponent.ts b/packages/Teams/js/src/adaptiveTeamsBotComponent.ts index 5a8ae0ad92..37f6e4b9b9 100644 --- a/packages/Teams/js/src/adaptiveTeamsBotComponent.ts +++ b/packages/Teams/js/src/adaptiveTeamsBotComponent.ts @@ -9,6 +9,7 @@ import { } from 'botbuilder-dialogs-adaptive-runtime-core'; import { + GetMeetingInfo, GetMeetingParticipant, GetMember, GetPagedMembers, @@ -40,6 +41,8 @@ import { OnTeamsChannelRenamed, OnTeamsChannelRestored, OnTeamsFileConsent, + OnTeamsMeetingStart, + OnTeamsMeetingEnd, OnTeamsMEBotMessagePreviewEdit, OnTeamsMEBotMessagePreviewSend, OnTeamsMECardButtonClicked, @@ -75,6 +78,10 @@ export class AdaptiveTeamsBotComponent extends BotComponent { getDeclarativeTypes() { return [ // Actions + { + kind: GetMeetingInfo.$kind, + type: GetMeetingInfo, + }, { kind: GetMeetingParticipant.$kind, type: GetMeetingParticipant, @@ -153,6 +160,8 @@ export class AdaptiveTeamsBotComponent extends BotComponent { type: OnTeamsChannelRestored, }, { kind: OnTeamsFileConsent.$kind, type: OnTeamsFileConsent }, + { kind: OnTeamsMeetingStart.$kind, type: OnTeamsMeetingStart }, + { kind: OnTeamsMeetingEnd.$kind, type: OnTeamsMeetingEnd }, { kind: OnTeamsMEBotMessagePreviewEdit.$kind, type: OnTeamsMEBotMessagePreviewEdit, diff --git a/packages/Teams/js/src/conditions/index.ts b/packages/Teams/js/src/conditions/index.ts index 47dc788d5a..22a5bd064d 100644 --- a/packages/Teams/js/src/conditions/index.ts +++ b/packages/Teams/js/src/conditions/index.ts @@ -9,6 +9,8 @@ export * from './onTeamsChannelDeleted'; export * from './onTeamsChannelRenamed'; export * from './onTeamsChannelRestored'; export * from './onTeamsFileConsent'; +export * from './onTeamsMeetingStart'; +export * from './onTeamsMeetingEnd'; export * from './onTeamsMEBotMessagePreviewEdit'; export * from './onTeamsMEBotMessagePreviewSend'; export * from './onTeamsMECardButtonClicked'; diff --git a/packages/Teams/js/src/conditions/onTeamsMeetingEnd.ts b/packages/Teams/js/src/conditions/onTeamsMeetingEnd.ts new file mode 100644 index 0000000000..55e49c6c51 --- /dev/null +++ b/packages/Teams/js/src/conditions/onTeamsMeetingEnd.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { Expression } from 'adaptive-expressions'; +import { Channels } from 'botbuilder'; +import { TurnPath } from 'botbuilder-dialogs'; +import { OnEventActivity } from 'botbuilder-dialogs-adaptive'; + +/** + * Actions triggered when a Teams Meeting End event is received. + * Note: turn.activity.value has meeting data. + */ +export class OnTeamsMeetingEnd extends OnEventActivity { + static $kind = 'Teams.OnMeetingEnd'; + + /** + * Create expression for this condition. + * + * @returns {Expression} An [Expression](xref:adaptive-expressions.Expression) used to evaluate this rule. + */ + protected createExpression(): Expression { + return Expression.andExpression( + Expression.parse( + `${TurnPath.activity}.channelId == '${Channels.Msteams}' && ${TurnPath.activity}.name == 'application/vnd.microsoft.meetingEnd'` + ), + super.createExpression() + ); + } +} diff --git a/packages/Teams/js/src/conditions/onTeamsMeetingStart.ts b/packages/Teams/js/src/conditions/onTeamsMeetingStart.ts new file mode 100644 index 0000000000..c940d2d705 --- /dev/null +++ b/packages/Teams/js/src/conditions/onTeamsMeetingStart.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { Expression } from 'adaptive-expressions'; +import { Channels } from 'botbuilder'; +import { TurnPath } from 'botbuilder-dialogs'; +import { OnEventActivity } from 'botbuilder-dialogs-adaptive'; + +/** + * Actions triggered when a Teams Meeting Start event is received. + * Note: turn.activity.value has meeting data. + */ +export class OnTeamsMeetingStart extends OnEventActivity { + static $kind = 'Teams.OnMeetingStart'; + + /** + * Create expression for this condition. + * + * @returns {Expression} An [Expression](xref:adaptive-expressions.Expression) used to evaluate this rule. + */ + protected createExpression(): Expression { + return Expression.andExpression( + Expression.parse( + `${TurnPath.activity}.channelId == '${Channels.Msteams}' && ${TurnPath.activity}.name == 'application/vnd.microsoft.meetingStart'` + ), + super.createExpression() + ); + } +} diff --git a/packages/Teams/js/src/index.ts b/packages/Teams/js/src/index.ts index dc1d9d0c69..7d89f5b014 100644 --- a/packages/Teams/js/src/index.ts +++ b/packages/Teams/js/src/index.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { AdaptiveTeamsBotComponent } from './adaptiveTeamsBotComponent'; /** * @module @microsoft/bot-components-teams */ export * from './actions'; -export * from './adaptiveTeamsBotComponent'; +export { AdaptiveTeamsBotComponent }; export * from './conditions'; +export default AdaptiveTeamsBotComponent; \ No newline at end of file