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

add Activityfactory #1401

Merged
merged 9 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion libraries/botbuilder-lg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"antlr4ts": "0.5.0-alpha.1",
"botframework-expressions": "4.1.6",
"lodash": "^4.17.11",
"uuid": "^3.3.3"
"uuid": "^3.3.3",
"botbuilder-core": "4.1.6"
},
"devDependencies": {
"@types/mocha": "^5.2.5",
Expand Down
361 changes: 361 additions & 0 deletions libraries/botbuilder-lg/src/activityFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
/**
* @module botbuilder-lg
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { Activity, SuggestedActions, Attachment, ActivityTypes, ActionTypes, CardAction } from 'botframework-schema';
import { MessageFactory, CardFactory } from 'botbuilder-core';

export class ActivityFactory {
private static GenericCardTypeMapping: Map<string, string> = new Map<string, string>
([
[ 'herocard', CardFactory.contentTypes.heroCard ],
[ 'thumbnailcard', CardFactory.contentTypes.thumbnailCard ],
[ 'audiocard', CardFactory.contentTypes.audioCard ],
[ 'videocard', CardFactory.contentTypes.videoCard ],
[ 'animationcard', CardFactory.contentTypes.animationCard ],
[ 'signincard', CardFactory.contentTypes.signinCard ],
[ 'oauthcard', CardFactory.contentTypes.oauthCard ],
]);

public static CreateActivity(lgStringResult: string): Activity {
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
let lgStructuredResult: any;
try {
lgStructuredResult = JSON.parse(lgStringResult);
} catch (error) {
return this.buildActivityFromText(lgStructuredResult.trim());
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
}

return this.buildActivityFromLGStructuredResult(lgStructuredResult);
}

private static buildActivityFromText(text: string): Activity {
return MessageFactory.text(text, text) as Activity;
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
}

private static buildActivityFromLGStructuredResult(lgJObj: any): Activity {
let activity: any = {};
Danieladu marked this conversation as resolved.
Show resolved Hide resolved

const type: string = this.getStructureType(lgJObj);
if (ActivityFactory.GenericCardTypeMapping.has(type)) {
const attachment: Attachment = this.getAttachment(lgJObj);
if (attachment !== undefined) {
activity = MessageFactory.attachment(attachment);
}
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
} else if (type === 'activity') {
activity = this.buildActivityFromObject(lgJObj);
} else {
throw new Error(`type ${ type } is not support currently.`);
}

return activity;
}

private static buildActivityFromObject(lgJObj: any): Activity {
let activity: any = {};

if ('type' in lgJObj && lgJObj.type === 'event') {
activity = this.buildEventActivity(lgJObj);
} else {
activity = this.buildMessageActivity(lgJObj);
}

return activity;
}

private static buildEventActivity(lgJObj: any): Activity {
let activity: any = { type: ActivityTypes.Event };
for (const item of Object.keys(lgJObj)) {
const property: string = item.trim();
const value: any = lgJObj[item];
switch (property.toLowerCase()) {
case '$type':
break;
case 'name':
activity.name = value.toString();
break;
case 'value':
activity.value = value.toString();
break;
default:
console.log(`Skipping unknown activity property ${ property }`);
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
break;
}
}

return activity;
}

private static buildMessageActivity(lgJObj: any): Activity {
let activity: any = { type: ActivityTypes.Message };
for (const key of Object.keys(lgJObj)) {
const property: string = key.trim();
const value: any = lgJObj[key];

switch (property.toLowerCase()) {
case '$type':
break;
case 'text':
activity.text = value.toString();
break;
case 'speak':
activity.speak = value.toString();
break;
case 'inputhint':
activity.inputHint = value.toString();
break;
case 'attachments':
activity.attachments = this.getAttachments(value);
break;
case 'suggestedactions':
activity.suggestedActions = this.getSuggestions(value);
break;
case 'attachmentlayout':
activity.AttachmentLayout = value.toString();
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
default:
console.log(`Skipping unknown activity property ${ property }`);
break;
}
}

return activity;
}

private static getSuggestions(value: any): SuggestedActions {
let suggestedActions: SuggestedActions = {
actions : [],
to: []
};

let actions: any[] = this.normalizedToList(value);

for (const action of actions) {
if (typeof action === 'string') {
const actionStr: string = action.trim();
suggestedActions.actions.push({
type: ActionTypes.MessageBack,
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
title: actionStr,
displayText: actionStr,
text: actionStr,
value: actionStr
});
} else {
const cardAction: CardAction = this.getCardAction('', action);
if (cardAction !== undefined) {
suggestedActions.actions.push(cardAction);
}
}
}
Danieladu marked this conversation as resolved.
Show resolved Hide resolved

return suggestedActions;
}

private static getButtons(cardType: string, value: any): CardAction[] {
let buttons: any[] = [];
let actions: any[] = this.normalizedToList(value);

for (const action of actions) {
if (typeof action === 'string') {
const actionStr = action.trim();
if (cardType === CardFactory.contentTypes.signinCard ||cardType === CardFactory.contentTypes.oauthCard ) {
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
buttons.push({
type: ActionTypes.Signin,
title: actionStr,
value: actionStr
});
} else {
buttons.push({
type: ActionTypes.ImBack,
title: actionStr,
value: actionStr
});
}

} else {
const cardAction: CardAction = this.getCardAction(cardType, action);
if (cardAction !== undefined) {
buttons.push(cardAction);
}
}
}

return buttons;
}

private static getCardAction(cardType: string, cardActionJObj: any): CardAction {
const type: string = this.getStructureType(cardActionJObj);
let cardAction: any = {};

if (cardType === CardFactory.contentTypes.signinCard || cardType === CardFactory.contentTypes.oauthCard) {
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
cardAction.type = ActionTypes.Signin;
} else {
cardAction.type = ActionTypes.ImBack;
}

if(type !== 'cardaction') {
return undefined;
}

for (const key of Object.keys(cardActionJObj)) {
const property: string = key.trim();
const value: any = cardActionJObj[key];

switch (property.toLowerCase()) {
case 'type':
cardAction.type = value.toString();
break;
case 'title':
cardAction.title = value.toString();
break;
case 'value':
cardAction.value = value.toString();
break;
case 'displaytext':
cardAction.displayText = value.toString();
break;
case 'text':
cardAction.text = value.toString();
break;
case 'image':
cardAction.image = value.toString();
break;
default:
console.log(`Skipping unknown activity property ${ property }`);
break;
}
}

return cardAction as CardAction;
}

private static getStructureType(jObj: any): string {
let result = '';

if (jObj !== undefined) {
if ('$type' in jObj) {
result = jObj['$type'].toString();
} else if ('type' in jObj) {
result = jObj['type'].toString();
}
}

return result.trim().toLowerCase();
}

private static getAttachments(value: any): Attachment[] {
let attachments = [];
let attachmentsJsonList: any[] = this.normalizedToList(value);

for (const attachmentsJson of attachmentsJsonList) {
if (typeof attachmentsJson === 'object') {
const attachment = this.getAttachment(attachmentsJson);
if (attachment !== undefined) {
attachments.push(attachment);
}
}
}

return attachments;
}

private static getAttachment(lgJObj: any): Attachment {
let attachment: any = {};
const type: string = this.getStructureType(lgJObj);
if (ActivityFactory.GenericCardTypeMapping.has(type)) {
attachment = this.getCardAttachment(ActivityFactory.GenericCardTypeMapping.get(type), lgJObj);
} else if(type === 'adaptivecard') {
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
attachment.contentType = CardFactory.contentTypes.adaptiveCard;
attachment.content = lgJObj;
} else {
attachment = undefined;
}

return attachment as Attachment;
}

private static getCardAttachment(type: string, lgJObj: any): Attachment {
let card: any = {};

for (const key in lgJObj) {
const property: string = key.trim().toLowerCase();
const value: any = lgJObj[key];

switch (property) {
case 'title':
case 'subtitle':
case 'text':
case 'aspect':
case 'value':
card[property] = value;
break;
case 'connectionname':
card['connectionName'] = value;
break;

case 'image':
case 'images':
if (type === CardFactory.contentTypes.heroCard || type === CardFactory.contentTypes.thumbnailCard) {
if (!('images' in card)) {
card['images'] = [];
}

let imageList: string[] = this.normalizedToList(value).map((u): string => u.toString());
imageList.forEach( (u): any => card['images'].push({url : u}));
} else {
card['image'] = {url: value.toString()};
}
break;
case 'media':
if (!('media' in card)) {
card['media'] = [];
}

let mediaList: string[] = this.normalizedToList(value).map((u): string => u.toString());
mediaList.forEach( (u): any => card['media'].push({url : u}));
break;
case 'buttons':
if (!('buttons' in card)) {
card['buttons'] = [];
}

let buttons: any[] = this.getButtons(type, value);
buttons.forEach( (u): any => card[property].push(u));
break;
case 'autostart':
case 'shareable':
case 'autoloop':
if (value.toString().toLowerCase() === 'true') {
card[property] = true;
} else if (value.toString().toLowerCase() === 'false') {
card[property] = false;
}

break;
case '':
break;
default:
console.log(`Skipping unknown activity property ${ property }`);
break;
}
}

return {
contentType: type,
content: card
};
}

private static normalizedToList(item: any): any[] {
if (item === undefined) {
return [];
} else if (item instanceof Array){
Danieladu marked this conversation as resolved.
Show resolved Hide resolved
return item;
} else {
return [item];
}
}

}
1 change: 1 addition & 0 deletions libraries/botbuilder-lg/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './lgImport';
export * from './range';
export * from './position';
export * from './evaluationTarget';
export * from './activityFactory';
Loading