Skip to content

Commit

Permalink
fix httprequest, refactor inputs, inputsDialog, (#1451)
Browse files Browse the repository at this point in the history
add two more samples
  • Loading branch information
Qi Kang authored and Stevenic committed Dec 6, 2019
1 parent a8242b7 commit 53ba6f5
Show file tree
Hide file tree
Showing 21 changed files with 494 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class DeleteProperty<O extends object = {}> extends Dialog<O> {
}

public async beginDialog(dc: DialogContext): Promise<DialogTurnResult> {
dc.state.setValue(this.property, undefined);
dc.state.deleteValue(this.property);
return await dc.endDialog();
}
}
114 changes: 86 additions & 28 deletions libraries/botbuilder-dialogs-adaptive/src/actions/httpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { DialogTurnResult, DialogConfiguration, DialogContext, Dialog } from 'bo
import { ExpressionProperty, ExpressionPropertyValue } from '../expressionProperty';
import fetch, * as request from "node-fetch";
import { Activity } from 'botbuilder-core';
import * as stringTemplate from '../stringTemplate';
import { isString } from 'util';
import { Expression } from 'botframework-expressions';

export interface HttpRequestConfiguration extends DialogConfiguration {

Expand Down Expand Up @@ -53,27 +56,27 @@ export enum HttpMethod {
/**
* Http GET
*/
GET,
GET = "GET",

/**
* Http POST
*/
POST,
POST = "POST",

/**
* Http PATCH
*/
PATCH,
PATCH = "PATCH",

/**
* Http PUT
*/
PUT,
PUT = "PUT",

/**
* Http DELETE
*/
DELETE
DELETE = "DELETE"
}

export class HttpRequest<O extends object = {}> extends Dialog<O> {
Expand All @@ -86,17 +89,16 @@ export class HttpRequest<O extends object = {}> extends Dialog<O> {
/**
* Http Url
*/
public url?: ExpressionProperty<string>;
public url?: string;

/**
* Http Headers
*/
public headers?: ExpressionProperty<any>;

public headers?: object;
/**
* Http Body
*/
public body?: ExpressionProperty<any>;
public body?: object;

/**
* The response type of the response
Expand All @@ -109,18 +111,23 @@ export class HttpRequest<O extends object = {}> extends Dialog<O> {
public resultProperty?: string;

constructor();
constructor(method: HttpMethod, url: ExpressionPropertyValue<string>, headers: ExpressionPropertyValue<any>,
body: ExpressionPropertyValue<any>,
constructor(method: HttpMethod, url: string, headers: object,
body: object,
responseType: ResponsesTypes, resultProperty: string);
constructor(method?: HttpMethod, url?: ExpressionPropertyValue<string>, headers?: ExpressionPropertyValue<any>,
body?: ExpressionPropertyValue<any>,
constructor(method?: HttpMethod, url?: string, headers?: object,
body?: object,
responseType?: ResponsesTypes, resultProperty?: string) {
super();
this.method = method;
this.url = new ExpressionProperty(url);
this.headers = new ExpressionProperty(headers);
this.body = new ExpressionProperty(body);
this.responseType = responseType;
this.url = url;
this.headers = headers;
this.body = body;
if (responseType) {
this.responseType = responseType;
}
else {
this.responseType = ResponsesTypes.Json;
}
this.resultProperty = resultProperty;
}

Expand All @@ -137,20 +144,40 @@ export class HttpRequest<O extends object = {}> extends Dialog<O> {
/**
* TODO: replace the key value pair in json recursively
*/
const url = this.url.evaluate(this.id, dc.state);
const body = this.body.evaluate(this.id, dc.state);
const headers = this.headers.evaluate(this.id, dc.state);

const response = await fetch(url, {
method: this.method.toString(),
headers: headers,
body: body
});
const url = stringTemplate.format(this.url, dc);
const headers = this.headers;

const instanceBody = this.ReplaceBodyRecursively(dc, this.body);

const parsedBody = JSON.stringify(instanceBody);
const parsedHeaders = Object.assign({ 'Content-Type': 'application/json' }, headers);

let response: any;

switch (this.method) {
case HttpMethod.DELETE:
case HttpMethod.GET:
response = await fetch(url, {
method: this.method.toString(),
headers: parsedHeaders,
});
break;
case HttpMethod.PUT:
case HttpMethod.PATCH:
case HttpMethod.POST:
response = await fetch(url, {
method: this.method.toString(),
headers: parsedHeaders,
body: parsedBody,
});
break;
}

const jsonResult = await response.json();

let result: Result = {
headers: this.headers,
headers: headers,
statusCode: response.status,
reasonPhrase: response.statusText
};
Expand All @@ -173,10 +200,41 @@ export class HttpRequest<O extends object = {}> extends Dialog<O> {
}

if (this.resultProperty) {
dc.state.setValue(this.resultProperty, jsonResult);
dc.state.setValue(this.resultProperty, result);
}

return await dc.endDialog(result);
}

private ReplaceBodyRecursively(dc: DialogContext, unit: object) {
if (typeof unit === 'string') {
let text: string = unit as string;
if (text.startsWith('{') && text.endsWith('}')) {
text = text.slice(1, text.length - 1);
return new ExpressionProperty(text).evaluate(this.id, dc.state);
}
else {
return stringTemplate.format(text, dc);
}
}

if (Array.isArray(unit)) {
let result = [];
unit.forEach(child => {
result.push(this.ReplaceBodyRecursively(dc, child));
})
return result;
}

if (typeof unit === 'object') {
let result = {};
for (let key in unit) {
result[key] = this.ReplaceBodyRecursively(dc, unit[key]);
}
return result;
}

return await dc.endDialog(jsonResult);
return unit;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ExpressionProperty<T> {
}

// Evaluate expression
const { value, error } = expression.tryEvaluate(state);
const { value, error } = expression.tryEvaluate(state.getMemorySnapshot());
if (error) { throw new Error(`${stepId}: Error evaluating expression - ${error}`) }

// Patch @entity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ export enum AttachmentOutputFormat {
export class AttachmentInput extends InputDialog<InputDialogOptions> {

public outputFormat = AttachmentOutputFormat.first;

constructor();
constructor(valueProperty: string, prompt: PromptType);
constructor(valueProperty: string, value: ExpressionPropertyValue<any>, prompt: PromptType);
constructor(valueProperty?: string, value?: ExpressionPropertyValue<any>|PromptType, prompt?: PromptType) {
constructor(property: string, prompt: PromptType);
constructor(property: string, value: ExpressionPropertyValue<any>, prompt: PromptType);
constructor(property?: string, value?: ExpressionPropertyValue<any> | PromptType, prompt?: PromptType) {
super();
if (valueProperty) {
if(!prompt) {
if (property) {
if (!prompt) {
prompt = value as PromptType;
value = undefined;
}
this.valueProperty = valueProperty;
this.property = property;
if (value !== undefined) { this.value = new ExpressionProperty(value as any) }
this.prompt.value = prompt;
}
Expand All @@ -51,10 +51,10 @@ export class AttachmentInput extends InputDialog<InputDialogOptions> {
const attachments = dc.context.activity.attachments;
return Array.isArray(attachments) && attachments.length > 0 ? attachments : undefined;
}

protected async onRecognizeInput(dc: DialogContext, consultation: boolean): Promise<InputState> {
// Recognize input and filter out non-attachments
let input: Attachment|Attachment[] = dc.state.getValue(InputDialog.VALUE_PROPERTY);
let input: Attachment | Attachment[] = dc.state.getValue(InputDialog.VALUE_PROPERTY);
const attachments = Array.isArray(input) ? input : [input];
const first = attachments.length > 0 ? attachments[0] : undefined;
if (typeof first != 'object' || (!first.contentUrl && !first.content)) {
Expand Down
22 changes: 11 additions & 11 deletions libraries/botbuilder-dialogs-adaptive/src/input/choiceInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ExpressionPropertyValue, ExpressionProperty } from "../expressionProper

export interface ChoiceInputConfiguration extends InputDialogConfiguration {
outputFormat?: ChoiceOutputFormat;
choices?: ChoiceList|ExpressionPropertyValue<ChoiceList>;
choices?: ChoiceList | ExpressionPropertyValue<ChoiceList>;
appendChoices?: boolean;
defaultLocale?: string;
style?: ListStyle;
Expand All @@ -29,7 +29,7 @@ export interface ChoiceInputOptions extends InputDialogOptions {
choices: ChoiceList;
}

export type ChoiceList = (string|Choice)[];
export type ChoiceList = (string | Choice)[];

export class ChoiceInput extends InputDialog<ChoiceInputOptions> {
/**
Expand Down Expand Up @@ -75,19 +75,19 @@ export class ChoiceInput extends InputDialog<ChoiceInputOptions> {
public recognizerOptions?: FindChoicesOptions;

constructor();
constructor(valueProperty: string, prompt: PromptType, choices: ChoiceList|ExpressionPropertyValue<ChoiceList>);
constructor(valueProperty: string, value: ExpressionPropertyValue<any>, prompt: PromptType, choices: ChoiceList|ExpressionPropertyValue<ChoiceList>);
constructor(valueProperty?: string, value?: ExpressionPropertyValue<any>|PromptType, prompt?: PromptType|ChoiceList|ExpressionPropertyValue<ChoiceList>, choices?: ChoiceList|ExpressionPropertyValue<ChoiceList>) {
constructor(property: string, prompt: PromptType, choices: ChoiceList | ExpressionPropertyValue<ChoiceList>);
constructor(property: string, value: ExpressionPropertyValue<any>, prompt: PromptType, choices: ChoiceList | ExpressionPropertyValue<ChoiceList>);
constructor(property?: string, value?: ExpressionPropertyValue<any> | PromptType, prompt?: PromptType | ChoiceList | ExpressionPropertyValue<ChoiceList>, choices?: ChoiceList | ExpressionPropertyValue<ChoiceList>) {
super();
if (valueProperty) {
if(choices == undefined) {
choices = prompt as ChoiceList|ExpressionPropertyValue<any[]>;
if (property) {
if (choices == undefined) {
choices = prompt as ChoiceList | ExpressionPropertyValue<any[]>;
prompt = value;
value = undefined;
}

// Initialize properties
this.valueProperty = valueProperty;
this.property = property;
if (value !== undefined) { this.value = new ExpressionProperty(value as any) }
this.prompt.value = prompt as PromptType;

Expand All @@ -98,7 +98,7 @@ export class ChoiceInput extends InputDialog<ChoiceInputOptions> {
}

public configure(config: ChoiceInputConfiguration): this {
for(const key in config) {
for (const key in config) {
if (config.hasOwnProperty(key)) {
const value = config[key];
switch (key) {
Expand Down Expand Up @@ -138,7 +138,7 @@ export class ChoiceInput extends InputDialog<ChoiceInputOptions> {
}
return super.onInitializeOptions(dc, options);
}

protected async onRecognizeInput(dc: DialogContext, consultation: boolean): Promise<InputState> {
// Get input and options
let input: string = dc.state.getValue(InputDialog.VALUE_PROPERTY).toString();
Expand Down
32 changes: 16 additions & 16 deletions libraries/botbuilder-dialogs-adaptive/src/input/confirmInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ export class ConfirmInput extends InputDialog<InputDialogOptions> {
/**
* Default options for rendering the choices to the user based on locale.
*/
private static defaultChoiceOptions: { [locale: string]: { choices: (string|Choice)[], options: ChoiceFactoryOptions }} = {
'es-es': { choices: ['Sí', 'No'], options: { inlineSeparator: ', ', inlineOr: ' o ', inlineOrMore: ', o ', includeNumbers: true }},
'nl-nl': { choices: ['Ja', 'Nee'], options: { inlineSeparator: ', ', inlineOr: ' of ', inlineOrMore: ', of ', includeNumbers: true }},
'en-us': { choices: ['Yes', 'No'], options: { inlineSeparator: ', ', inlineOr: ' or ', inlineOrMore: ', or ', includeNumbers: true }},
'fr-fr': { choices: ['Oui', 'Non'], options: { inlineSeparator: ', ', inlineOr: ' ou ', inlineOrMore: ', ou ', includeNumbers: true }},
'de-de': { choices: ['Ja', 'Nein'], options: { inlineSeparator: ', ', inlineOr: ' oder ', inlineOrMore: ', oder ', includeNumbers: true }},
'ja-jp': { choices: ['はい', 'いいえ'], options: { inlineSeparator: '、 ', inlineOr: ' または ', inlineOrMore: '、 または ', includeNumbers: true }},
'pt-br': { choices: ['Sim', 'Não'], options: { inlineSeparator: ', ', inlineOr: ' ou ', inlineOrMore: ', ou ', includeNumbers: true }},
'zh-cn': { choices: ['是的', '不'], options: { inlineSeparator: ', ', inlineOr: ' 要么 ', inlineOrMore: ', 要么 ', includeNumbers: true }}
private static defaultChoiceOptions: { [locale: string]: { choices: (string | Choice)[], options: ChoiceFactoryOptions } } = {
'es-es': { choices: ['Sí', 'No'], options: { inlineSeparator: ', ', inlineOr: ' o ', inlineOrMore: ', o ', includeNumbers: true } },
'nl-nl': { choices: ['Ja', 'Nee'], options: { inlineSeparator: ', ', inlineOr: ' of ', inlineOrMore: ', of ', includeNumbers: true } },
'en-us': { choices: ['Yes', 'No'], options: { inlineSeparator: ', ', inlineOr: ' or ', inlineOrMore: ', or ', includeNumbers: true } },
'fr-fr': { choices: ['Oui', 'Non'], options: { inlineSeparator: ', ', inlineOr: ' ou ', inlineOrMore: ', ou ', includeNumbers: true } },
'de-de': { choices: ['Ja', 'Nein'], options: { inlineSeparator: ', ', inlineOr: ' oder ', inlineOrMore: ', oder ', includeNumbers: true } },
'ja-jp': { choices: ['はい', 'いいえ'], options: { inlineSeparator: '、 ', inlineOr: ' または ', inlineOrMore: '、 または ', includeNumbers: true } },
'pt-br': { choices: ['Sim', 'Não'], options: { inlineSeparator: ', ', inlineOr: ' ou ', inlineOrMore: ', ou ', includeNumbers: true } },
'zh-cn': { choices: ['是的', '不'], options: { inlineSeparator: ', ', inlineOr: ' 要么 ', inlineOrMore: ', 要么 ', includeNumbers: true } }
};

/**
Expand Down Expand Up @@ -60,16 +60,16 @@ export class ConfirmInput extends InputDialog<InputDialogOptions> {
public confirmChoices?: ChoiceList;

constructor();
constructor(valueProperty: string, prompt: PromptType);
constructor(valueProperty: string, value: ExpressionPropertyValue<any>, prompt: PromptType);
constructor(valueProperty?: string, value?: ExpressionPropertyValue<any>|PromptType, prompt?: PromptType) {
constructor(property: string, prompt: PromptType);
constructor(property: string, value: ExpressionPropertyValue<any>, prompt: PromptType);
constructor(property?: string, value?: ExpressionPropertyValue<any> | PromptType, prompt?: PromptType) {
super();
if (valueProperty) {
if(!prompt) {
if (property) {
if (!prompt) {
prompt = value as PromptType;
value = undefined;
}
this.valueProperty = valueProperty;
this.property = property;
if (value !== undefined) { this.value = new ExpressionProperty(value as any) }
this.prompt.value = prompt;
}
Expand All @@ -82,7 +82,7 @@ export class ConfirmInput extends InputDialog<InputDialogOptions> {
protected onComputeId(): string {
return `ConfirmInput[]`;
}

protected async onRecognizeInput(dc: DialogContext, consultation: boolean): Promise<InputState> {
// Recognize input if needed
let input: any = dc.state.getValue(InputDialog.VALUE_PROPERTY);
Expand Down
Loading

0 comments on commit 53ba6f5

Please sign in to comment.