new(all): WebDav support for all bots.
This commit is contained in:
parent
b7bcd4f4c8
commit
95458a658d
15 changed files with 2397 additions and 14 deletions
|
@ -151,6 +151,7 @@
|
||||||
"keyv": "4.5.4",
|
"keyv": "4.5.4",
|
||||||
"koa": "2.15.3",
|
"koa": "2.15.3",
|
||||||
"koa-body": "6.0.1",
|
"koa-body": "6.0.1",
|
||||||
|
"koa-ratelimit": "5.1.0",
|
||||||
"koa-router": "12.0.1",
|
"koa-router": "12.0.1",
|
||||||
"langchain": "0.2.17",
|
"langchain": "0.2.17",
|
||||||
"language-tags": "1.0.9",
|
"language-tags": "1.0.9",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
@ -44,21 +43,34 @@ import { createKoaHttpMiddleware } from '@push-rpc/http';
|
||||||
import { GBServer } from '../../src/app.js';
|
import { GBServer } from '../../src/app.js';
|
||||||
import { SocketServer } from '@push-rpc/core';
|
import { SocketServer } from '@push-rpc/core';
|
||||||
import * as koaBody from 'koa-body';
|
import * as koaBody from 'koa-body';
|
||||||
|
import ratelimit from 'koa-ratelimit';
|
||||||
|
|
||||||
export function createKoaHttpServer(
|
export function createKoaHttpServer(port: number, getRemoteId: (ctx: Koa.Context) => string, opts: {}): SocketServer {
|
||||||
port: number,
|
const { onError, onConnection, middleware } = createKoaHttpMiddleware(getRemoteId);
|
||||||
getRemoteId: (ctx: Koa.Context) => string,
|
|
||||||
opts:{}
|
|
||||||
): SocketServer {
|
|
||||||
const { onError, onConnection, middleware } =
|
|
||||||
createKoaHttpMiddleware(getRemoteId);
|
|
||||||
|
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
|
|
||||||
|
// Apply the rate-limiting middleware
|
||||||
|
app.use(
|
||||||
|
ratelimit({
|
||||||
|
driver: 'memory', // Use 'memory' for in-memory store
|
||||||
|
duration: 60000, // 1 minute window
|
||||||
|
errorMessage: 'Slow down your requests',
|
||||||
|
id: ctx => ctx.ip, // Identify client by IP address
|
||||||
|
headers: {
|
||||||
|
remaining: 'X-RateLimit-Remaining',
|
||||||
|
reset: 'X-RateLimit-Reset',
|
||||||
|
total: 'X-RateLimit-Limit'
|
||||||
|
},
|
||||||
|
max: 100, // Limit each IP to 100 requests per window
|
||||||
|
disableHeader: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
app.use(cors({ origin: '*' }));
|
app.use(cors({ origin: '*' }));
|
||||||
app.use(koaBody.koaBody({jsonLimit:'1024mb',textLimit:'1024mb', formLimit:'1024mb',
|
app.use(koaBody.koaBody({ jsonLimit: '1024mb', textLimit: '1024mb', formLimit: '1024mb', multipart: true }));
|
||||||
multipart: true }));
|
|
||||||
app.use(middleware);
|
app.use(middleware);
|
||||||
const server = app.listen(port);
|
const server = app.listen(port);
|
||||||
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set.
|
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set.
|
||||||
server.timeout = SERVER_TIMEOUT;
|
server.timeout = SERVER_TIMEOUT;
|
||||||
|
|
||||||
|
@ -100,7 +112,7 @@ export class GBBasicPackage implements IGBPackage {
|
||||||
}
|
}
|
||||||
public async loadBot(min: GBMinInstance): Promise<void> {
|
public async loadBot(min: GBMinInstance): Promise<void> {
|
||||||
const botId = min.botId;
|
const botId = min.botId;
|
||||||
GBServer.globals.debuggers[botId] = {};
|
GBServer.globals.debuggers[botId] = {};
|
||||||
GBServer.globals.debuggers[botId].state = 0;
|
GBServer.globals.debuggers[botId].state = 0;
|
||||||
GBServer.globals.debuggers[botId].breaks = [];
|
GBServer.globals.debuggers[botId].breaks = [];
|
||||||
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
||||||
|
|
|
@ -1016,7 +1016,8 @@ export class GBDeployer implements IGBDeployer {
|
||||||
'google-chat.gblib',
|
'google-chat.gblib',
|
||||||
'teams.gblib',
|
'teams.gblib',
|
||||||
'hubspot.gblib',
|
'hubspot.gblib',
|
||||||
'llm.gblib'
|
'llm.gblib',
|
||||||
|
'saas.gbapp'
|
||||||
];
|
];
|
||||||
|
|
||||||
return names.indexOf(name) > -1;
|
return names.indexOf(name) > -1;
|
||||||
|
|
445
packages/default.gbui/src/components/Debugger.js
Normal file
445
packages/default.gbui/src/components/Debugger.js
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
// import * as React from "react";
|
||||||
|
// import Header from "./Header";
|
||||||
|
// import HeroList, { HeroListItem } from "./HeroList";
|
||||||
|
// import Progress from "./Progress";
|
||||||
|
// import "../../../assets/icon-16.png";
|
||||||
|
// import "../../../assets/icon-32.png";
|
||||||
|
// import "../../../assets/icon-80.png";
|
||||||
|
// import $ from "jquery";
|
||||||
|
|
||||||
|
// export interface AppProps {
|
||||||
|
// title: string;
|
||||||
|
// isOfficeInitialized: boolean;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface AppState {
|
||||||
|
// listItems: HeroListItem[];
|
||||||
|
// mode: number;
|
||||||
|
// conversationText: string;
|
||||||
|
// scope: string;
|
||||||
|
// state: number;
|
||||||
|
// stateInfo: string;
|
||||||
|
// inputText: string;
|
||||||
|
// messages: string;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default class App extends React.Component<AppProps, AppState> {
|
||||||
|
// constructor(props, context) {
|
||||||
|
// super(props, context);
|
||||||
|
// this.state = {
|
||||||
|
// mode: 0,
|
||||||
|
// listItems: [],
|
||||||
|
// conversationText: "",
|
||||||
|
// scope: "",
|
||||||
|
// state: 0,
|
||||||
|
// stateInfo: "",
|
||||||
|
// messages: "",
|
||||||
|
// inputText: "",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// botId = "dev-rodriguez22";
|
||||||
|
// botKey = "starter";
|
||||||
|
// host = "https://tender-yak-44.telebit.io";
|
||||||
|
// breakpointsMap = {};
|
||||||
|
|
||||||
|
// componentDidMount() {
|
||||||
|
// this.setState({
|
||||||
|
// listItems: [
|
||||||
|
// {
|
||||||
|
// icon: "Ribbon",
|
||||||
|
// primaryText: "Office integration to Bots",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// icon: "Unlock",
|
||||||
|
// primaryText: "Unlock features of General Bots",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// icon: "Design",
|
||||||
|
// primaryText: "Create your Bots using BASIC",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// context = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/getContext`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function (item) {
|
||||||
|
// console.log("GBWord Add-in: context OK.");
|
||||||
|
// const line = item.line;
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// if (i === line) {
|
||||||
|
// paragraph.font.highlightColor = "Yellow";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// setExecutionLine = async (line) => {
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// if (i === line) {
|
||||||
|
// paragraph.font.highlightColor = "Yellow";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// breakpoint = async () => {
|
||||||
|
// let line = 0;
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// let selection = context.document.getSelection();
|
||||||
|
// selection.load();
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// console.log("Empty selection, cursor.");
|
||||||
|
|
||||||
|
// const paragraph = selection.paragraphs.getFirst();
|
||||||
|
// paragraph.select();
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph1 = paragraphs.items[i];
|
||||||
|
|
||||||
|
// if (paragraph1 === paragraph) {
|
||||||
|
// line = i + 1;
|
||||||
|
// paragraph.font.highlightColor = "Orange";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return context.sync();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/setBreakpoint`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, line },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: breakpoint OK.");
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// refactor = async () => {
|
||||||
|
// let line = 0;
|
||||||
|
|
||||||
|
// let change = 'ssssssssssssssssssss';
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// let selection = context.document.getSelection();
|
||||||
|
// selection.load();
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// var paragraphs = selection.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// let code = '';
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// code += paragraph.text;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/refactor`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, code: code, change: change },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(async function (data) {
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var selectedRange = context.document.getSelection();
|
||||||
|
// context.load(selectedRange, "text");
|
||||||
|
// selectedRange.text = data;
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return context.sync();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
// resume = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/resume`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: resume OK.");
|
||||||
|
// this.setState({ mode: 1 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// step = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/step`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: step OK.");
|
||||||
|
// this.setState({ mode: 2 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// stop = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/stop`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: stop OK.");
|
||||||
|
// this.setState({ mode: 0 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// sendMessage = async (args) => {
|
||||||
|
// if (args.keyCode === 13) {
|
||||||
|
// const text = args.target.value;
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/sendMessage`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, text: text },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: sendMessage OK.");
|
||||||
|
// args.target.value = "";
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// waitFor = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
|
||||||
|
|
||||||
|
// refresh = async () => {
|
||||||
|
// const context = await this.context();
|
||||||
|
|
||||||
|
// this.setState({
|
||||||
|
// conversationText: context['conversationText'],
|
||||||
|
// state: context['state'],
|
||||||
|
// messages: context['messages'],
|
||||||
|
// scope: context['scope'],
|
||||||
|
// mode: context['state']
|
||||||
|
// });
|
||||||
|
// await this.waitFor(3000);
|
||||||
|
// await this.refresh();
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
// debug = async () => {
|
||||||
|
// if (this.state.mode === 0) {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/start`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, scriptName: "auto" },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: debug OK.");
|
||||||
|
// this.state.mode = 1;
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// } else if (this.state.mode === 2) {
|
||||||
|
// this.resume();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await this.refresh();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// formatCode = async () => {
|
||||||
|
// return Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// const words = paragraph.split([" "], true /* trimDelimiters*/, true /* trimSpaces */);
|
||||||
|
// words.load(["text", "font"]);
|
||||||
|
// await context.sync();
|
||||||
|
// var boldWords = [];
|
||||||
|
// for (var j = 0; j < words.items.length; ++j) {
|
||||||
|
// var word = words.items[j];
|
||||||
|
// if (word.text === "TALK" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "HEAR" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "SAVE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "FIND" && j == 3) boldWords.push(word);
|
||||||
|
// if (word.text === "OPEN" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "WAIT" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "SET" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "CLICK" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "MERGE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "IF" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "THEN" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "ELSE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "END" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "TWEET" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "HOVER" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "PRESS" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "DO" && j == 0) boldWords.push(word);
|
||||||
|
// }
|
||||||
|
// for (var j = 0; j < boldWords.length; ++j) {
|
||||||
|
// boldWords[j].font.color = "blue";
|
||||||
|
// boldWords[j].font.bold = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// render() {
|
||||||
|
// const { title, isOfficeInitialized } = this.props;
|
||||||
|
|
||||||
|
// if (!isOfficeInitialized) {
|
||||||
|
// return (
|
||||||
|
// <Progress title={title} logo="assets/logo-filled.png" message="Please sideload your addin to see app body." />
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <div className="ms-welcome">
|
||||||
|
// <Header logo="assets/logo-filled.png" title={this.props.title} message="Welcome" />
|
||||||
|
//
|
||||||
|
// <a onClick={this.formatCode} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--DocumentApproval`} title="Format"></i>
|
||||||
|
// Format
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.debug} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--AirplaneSolid`} title="Run"></i>
|
||||||
|
// Run
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.stop} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--StopSolid`} title="Stop"></i>
|
||||||
|
// Stop
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.step} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--Next`} title="Step Over"></i>
|
||||||
|
// Step
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.breakpoint} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--DRM`} title="Set Breakpoint"></i>
|
||||||
|
// Break
|
||||||
|
// </a>
|
||||||
|
// <br />
|
||||||
|
// <br />
|
||||||
|
// <div>Status: {this.state.stateInfo} </div>
|
||||||
|
// <br />
|
||||||
|
// <div>Bot Messages:</div>
|
||||||
|
// <textarea title="Bot Messages" value={this.state.conversationText} readOnly={true}></textarea>
|
||||||
|
// <br />
|
||||||
|
// <textarea
|
||||||
|
// title="Message"
|
||||||
|
// readOnly={false}
|
||||||
|
// onKeyDown={this.sendMessage}
|
||||||
|
// ></textarea>
|
||||||
|
// <div>Variables:</div>
|
||||||
|
// <div>{this.state.scope} </div>
|
||||||
|
// <HeroList message="Discover what General Bots can do for you today!!" items={this.state.listItems}></HeroList>
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -132,7 +132,7 @@ export class GBLLMOutputParser extends BaseLLMOutputParser<ExpectedOutput> {
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
GBLogEx.info(this.min, result);
|
GBLogEx.info(this.min, result);
|
||||||
result = result.replace(/\\n/g, '');
|
result = result. replace(/\\n/g, '');
|
||||||
result = result.replace(/\`\`\`/g, '');
|
result = result.replace(/\`\`\`/g, '');
|
||||||
res = JSON.parse(result);
|
res = JSON.parse(result);
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -314,6 +314,7 @@ export class ChatServices {
|
||||||
model = new ChatOpenAI({
|
model = new ChatOpenAI({
|
||||||
azureOpenAIApiKey: azureOpenAIKey,
|
azureOpenAIApiKey: azureOpenAIKey,
|
||||||
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
|
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
|
||||||
|
|
||||||
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
|
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
|
||||||
azureOpenAIApiVersion: azureOpenAIVersion,
|
azureOpenAIApiVersion: azureOpenAIVersion,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
|
5
packages/saas.gbapp/PRESS-RELEASE.md
Executable file
5
packages/saas.gbapp/PRESS-RELEASE.md
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
The community needs a common platform to build bots on top of BOT Framework or any framework that can be added in the future to General Bots. People will need to create lots of custom personal assistants crossing entities like bots, knowledge, personality, branding, style. But now they only have frameworks that allow the bot creation but with no AI ecosystem in mind. Industry has proven to be a good ground for starting Robotic Process Automation through bots, but often lack of specialized hand-word and does not see as forecast to a digital transformation anchor.
|
||||||
|
This platform is proposed to be the one in terms of democratizing the community through bot building. It's community driven and has a lot to offer as a quick start to the bot automation world primarily based on Microsoft platform. So people who does not know how to program can start a new bot from Excel, Word, OneNote, or any piece of information. The package system is the base for the Marketplace which currently offer knowledge, themes, bots and custom bot UIs and can offer several classes of packages which compounds the entire AI body.
|
||||||
|
Using Azure and Cognitive Services we have created a community for General Bots which allow anyone to build their bot by using common tools like Excel and Photoshop. The administration is done by conversation and packages are easily deployed and maintained.
|
||||||
|
The adoption is much like SharePoint. When someone needs a site, they create a New Site. General Bots can do the same just copying and pasting some files in Windows Explorer.
|
||||||
|
The community builds packages using TypeScript (currently) and Python (future) and publish it through General Bots store and share the core through all vendors. A sample .gbapp package for Azure Active Directory Reset password is provided at https://github.com/pragmatismo-io/AzureADPasswordReset.gbapp.
|
304
packages/saas.gbapp/dialog/NewUserDialog.ts
Executable file
304
packages/saas.gbapp/dialog/NewUserDialog.ts
Executable file
|
@ -0,0 +1,304 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { IGBDialog, GBMinInstance } from 'botlib';
|
||||||
|
import { Messages } from '../strings.js';
|
||||||
|
import { MainService } from '../service/MainService.js';
|
||||||
|
import { Package } from '../index.js';
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
|
||||||
|
export class NewUserDialog extends IGBDialog {
|
||||||
|
static getBotNameDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_botname',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
await step.prompt('textPrompt', Messages[locale].whats_botname);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/[_a-zA-Z][_a-zA-Z0-9]{0,16}/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(step.context.activity.originalText);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await step.context.sendActivity(Messages[locale].validation_enter_valid_botname);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_botname', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const botName = value[0];
|
||||||
|
if (await min.deployService.botExists(botName)) {
|
||||||
|
await step.context.sendActivity(`O Bot ${botName} já existe. Escolha por favor, outro nome!`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_botname', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
step.activeDialog.state.options.botName = botName;
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_bottemplate', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getBotTemplateDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_bottemplate',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity('Aqui estão alguns modelos para você escolher:');
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
const list = await gboService.listTemplates(min);
|
||||||
|
|
||||||
|
let templateMessage = undefined;
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
if (item.name !== 'Shared.gbai') {
|
||||||
|
templateMessage = templateMessage ? `${templateMessage}\n- ${item.name}` : `- ${item.name}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await step.context.sendActivity(templateMessage);
|
||||||
|
|
||||||
|
step.activeDialog.state.options.templateList = list;
|
||||||
|
return await step.prompt('textPrompt', `Qual modelo de bot você gostaria de usar?`);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const list = step.activeDialog.state.options.templateList;
|
||||||
|
let template = null;
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
if (gboService.kmpSearch(step.context.activity.originalText, item.name) != -1) {
|
||||||
|
template = item.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (template === null) {
|
||||||
|
await step.context.sendActivity(`Escolha, por favor, um destes modelos listados.`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_bottemplate', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
step.activeDialog.state.options.templateName = template;
|
||||||
|
debugger;
|
||||||
|
await NewUserDialog.createBot(step, min, true);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromCC(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_cc',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].thanks_payment);
|
||||||
|
await NewUserDialog.createBot(step, min, false);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromDocument(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_document',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_payment';
|
||||||
|
|
||||||
|
return await step.replaceDialog('/bank_payment_type', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromPayment(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_payment',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
if (step.activeDialog.state.options.paymentType === 'cc') {
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_cc';
|
||||||
|
await step.replaceDialog(`/bank_ccnumber`, step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].boleto_mail);
|
||||||
|
|
||||||
|
await step.context.sendActivity('textPrompt', Messages[locale].thanks_payment);
|
||||||
|
await NewUserDialog.createBot(step, min, false);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getVoucherDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_voucher',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.prompt('textPrompt', Messages[locale].own_voucher);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
if (step.result.toLowerCase() === 'gb2020') {
|
||||||
|
await NewUserDialog.createBot(step, min, true);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
} else {
|
||||||
|
// return await step.replaceDialog('/welcome_saas_voucher', 'Os meios de pagamento estão neste momento desabilitados, por favor informe um voucher ou contate info@pragmatismo.cloud.');
|
||||||
|
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_document';
|
||||||
|
return await step.replaceDialog('/xrm_document', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async createBot(step: any, min: GBMinInstance, free: boolean) {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].ok_procceding_creation);
|
||||||
|
const url = `https://gb.pragmatismo.cloud/${step.activeDialog.state.options.botName}`;
|
||||||
|
await step.context.sendActivity(Messages[locale].bot_created(url));
|
||||||
|
const service = new MainService();
|
||||||
|
await service.createSubscription(
|
||||||
|
min,
|
||||||
|
step.activeDialog.state.options.name,
|
||||||
|
step.activeDialog.state.options.document,
|
||||||
|
step.activeDialog.state.options.email,
|
||||||
|
step.activeDialog.state.options.mobile,
|
||||||
|
step.activeDialog.state.options.botName,
|
||||||
|
step.activeDialog.state.options.ccNumber,
|
||||||
|
step.activeDialog.state.options.ccExpiresOnMonth,
|
||||||
|
step.activeDialog.state.options.ccExpiresOnYear,
|
||||||
|
step.activeDialog.state.options.ccSecuritycode,
|
||||||
|
step.activeDialog.state.options.templateName,
|
||||||
|
free
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDialogBatch(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_batch',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].welcome);
|
||||||
|
|
||||||
|
await step.prompt('textPrompt', `Please, inform bot names separeted by comma (,).`);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
const service = new MainService();
|
||||||
|
|
||||||
|
const bots = step.context.activity.originalText.split(',');
|
||||||
|
bots.forEach(async botName => {
|
||||||
|
await service.createSubscription(
|
||||||
|
min,
|
||||||
|
botName,
|
||||||
|
'999999999',
|
||||||
|
'operations@pragmatismo.cloud',
|
||||||
|
'5521999998888',
|
||||||
|
botName,
|
||||||
|
null,
|
||||||
|
'12',
|
||||||
|
'99',
|
||||||
|
'1234',
|
||||||
|
'Starter.gbai',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
step.activeDialog.state.options.document = null;
|
||||||
|
step.activeDialog.state.options.email = null;
|
||||||
|
step.activeDialog.state.options.botName = null;
|
||||||
|
step.activeDialog.state.options.ccNumber = null;
|
||||||
|
step.activeDialog.state.options.ccExpiresOnMonth = null;
|
||||||
|
step.activeDialog.state.options.ccExpiresOnYear = null;
|
||||||
|
step.activeDialog.state.options.ccSecuritycode = null;
|
||||||
|
step.activeDialog.state.options.templateName = null;
|
||||||
|
|
||||||
|
await step.context.sendActivity(Messages[locale].welcome);
|
||||||
|
|
||||||
|
const mobile = step.context.activity.from.id;
|
||||||
|
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_botname';
|
||||||
|
|
||||||
|
if (isNaN(mobile as any)) {
|
||||||
|
await step.context.sendActivity(Messages[locale].ok_get_information);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/profile_name', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const name = Package.welcomes ? Package.welcomes[mobile] : null;
|
||||||
|
step.activeDialog.state.options.name = name;
|
||||||
|
step.activeDialog.state.options.mobile = mobile;
|
||||||
|
|
||||||
|
await step.context.sendActivity(`Olá ${name}, vamos criar o seu Bot agora.`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/profile_email', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
195
packages/saas.gbapp/index.ts
Executable file
195
packages/saas.gbapp/index.ts
Executable file
|
@ -0,0 +1,195 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { IGBPackage, GBMinInstance, IGBCoreService, GBLog, IGBAdminService, GBDialogStep } from 'botlib'
|
||||||
|
import { Sequelize } from 'sequelize-typescript'
|
||||||
|
import { GBOnlineSubscription } from './model/MainModel'
|
||||||
|
|
||||||
|
import { MSSubscriptionService } from './service/MSSubscription'
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
import { NewUserDialog } from './dialog/NewUserDialog'
|
||||||
|
const MicrosoftGraph = require("@microsoft/microsoft-graph-client");
|
||||||
|
|
||||||
|
const cron = require('node-cron');
|
||||||
|
|
||||||
|
export class Package implements IGBPackage {
|
||||||
|
sysPackages: IGBPackage[]
|
||||||
|
adminService: IGBAdminService;
|
||||||
|
public static welcomes = {};
|
||||||
|
instanceId: any
|
||||||
|
|
||||||
|
public getDialogs(min: GBMinInstance) {
|
||||||
|
return [NewUserDialog.getDialog(min),
|
||||||
|
NewUserDialog.getBotNameDialog(min),
|
||||||
|
NewUserDialog.getVoucherDialog(min),
|
||||||
|
NewUserDialog.getBotTemplateDialog(min),
|
||||||
|
NewUserDialog.getReturnFromPayment(min),
|
||||||
|
NewUserDialog.getReturnFromCC(min),
|
||||||
|
NewUserDialog.getReturnFromDocument(min),
|
||||||
|
NewUserDialog.getDialogBatch(min)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||||
|
sequelize.addModels([GBOnlineSubscription]);
|
||||||
|
core.setWWWRoot(process.env.SAAS_WWWROOT);
|
||||||
|
core.setEntryPointDialog('/welcome_saas');
|
||||||
|
|
||||||
|
// Installs webhook for Microsoft intercommunication.
|
||||||
|
|
||||||
|
core.installWebHook(true, '/mslanding', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSLanding(req, res);
|
||||||
|
});
|
||||||
|
core.installWebHook(true, '/mshook', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSHook(req, res);
|
||||||
|
});
|
||||||
|
core.installWebHook(true, '/signup', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSSignUp(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setups schedule to trigger notifications as pro-active messages.
|
||||||
|
*/
|
||||||
|
private setupScheduler(min, sendToDevice) {
|
||||||
|
const schedule = '30 09 * * 1-5';
|
||||||
|
const options = {
|
||||||
|
scheduled: true,
|
||||||
|
timezone: 'America/Sao_Paulo'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.adminService = min.adminService;
|
||||||
|
this.instanceId = min.instanceId;
|
||||||
|
|
||||||
|
cron.schedule(schedule, async () => {
|
||||||
|
GBLog.info( 'Sending Tasks notifications if applies...');
|
||||||
|
await this.notifyJob(sendToDevice);
|
||||||
|
}, options);
|
||||||
|
GBLog.info( 'Running Reviews notifications 09:30 from Monday to Friday...');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by scheduler to send notification message to phones.
|
||||||
|
* @param sendToDevice The function used to notify.
|
||||||
|
*/
|
||||||
|
private async notifyJob(sendToDevice) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async getTasksMarkdown(path, file) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await this.adminService.acquireElevatedToken(this.instanceId);
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let res = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:${path}:/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let document = res.value.filter(m => {
|
||||||
|
return m.name === file
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${document[0].id}/workbook/worksheets('Tasks')/range(address='A1:A10')`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let index = 1;
|
||||||
|
let md = `*Tasks*\n`;
|
||||||
|
|
||||||
|
for (; index <= 10; index++) {
|
||||||
|
const row = results.text[index];
|
||||||
|
if (row !== undefined) {
|
||||||
|
md = `${md}\n *${index}*. ${row[0]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
async unloadPackage(core: IGBCoreService): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadBot(min: GBMinInstance): Promise<void> {
|
||||||
|
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
|
||||||
|
|
||||||
|
// Gets the sendToDevice method of whatsapp.gblib and setups scheduler.
|
||||||
|
|
||||||
|
if (min.whatsAppDirectLine !== undefined && min.botId === "Pragmatismo") {
|
||||||
|
const sendToDevice = min.whatsAppDirectLine.sendToDevice.bind(min.whatsAppDirectLine);
|
||||||
|
this.setupScheduler(min, sendToDevice);
|
||||||
|
this.notifyJob(sendToDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async unloadBot(min: GBMinInstance): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case "whatsappMessage":
|
||||||
|
|
||||||
|
const from = data.from;
|
||||||
|
const fromName = data.fromName;
|
||||||
|
Package.welcomes[from] = fromName;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GBLog.verbose('saas.gbapp onExchangeData called');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
packages/saas.gbapp/model/MainModel.ts
Executable file
81
packages/saas.gbapp/model/MainModel.ts
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
Column,
|
||||||
|
Model,
|
||||||
|
HasMany,
|
||||||
|
BelongsTo,
|
||||||
|
BelongsToMany,
|
||||||
|
Length,
|
||||||
|
ForeignKey,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DataType,
|
||||||
|
IsUUID,
|
||||||
|
PrimaryKey,
|
||||||
|
AutoIncrement
|
||||||
|
} from "sequelize-typescript"
|
||||||
|
|
||||||
|
@Table({ tableName: 'GBOnlineSubscription' })
|
||||||
|
export class GBOnlineSubscription extends Model<GBOnlineSubscription> {
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
@AutoIncrement
|
||||||
|
@Column
|
||||||
|
Id: number
|
||||||
|
|
||||||
|
@Column
|
||||||
|
instanceId: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
externalSubscriptionId: string // MSFT or
|
||||||
|
|
||||||
|
@Column
|
||||||
|
saasSubscriptionStatus: string
|
||||||
|
|
||||||
|
@Column
|
||||||
|
isFreeTrial: boolean
|
||||||
|
|
||||||
|
@Column
|
||||||
|
planId: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
lastCCFourDigits: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
status: string;
|
||||||
|
}
|
354
packages/saas.gbapp/service/GBOService.ts
Executable file
354
packages/saas.gbapp/service/GBOService.ts
Executable file
|
@ -0,0 +1,354 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { GBMinInstance, GBLog } from "botlib";
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
const MicrosoftGraph = require("@microsoft/microsoft-graph-client");
|
||||||
|
const Juno = require('juno-payment-node');
|
||||||
|
const sgMail = require('@sendgrid/mail');
|
||||||
|
const PasswordGenerator = require('strict-password-generator').default;
|
||||||
|
|
||||||
|
export class GBOService {
|
||||||
|
|
||||||
|
public isValidCardNumber(ccNumber) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateNumber(ccNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValidSecurityCode(ccNumber, cvcNumber) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateCvc(ccNumber, cvcNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValidExpireDate(month, year) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateExpireDate(month, year);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendEmail(token: string, to: string, from: string,
|
||||||
|
subject: string, text: string, html: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
sgMail.setApiKey(token);
|
||||||
|
const msg = {
|
||||||
|
to: to,
|
||||||
|
from: from,
|
||||||
|
subject: subject,
|
||||||
|
text: text,
|
||||||
|
html: html
|
||||||
|
};
|
||||||
|
sgMail.send(msg, false, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createSubFolderAtRoot(token: string, name: string,
|
||||||
|
siteId: string, libraryId: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const body = {
|
||||||
|
"name": name,
|
||||||
|
"folder": {},
|
||||||
|
"@microsoft.graph.conflictBehavior": "rename"
|
||||||
|
}
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root/children`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public async createSubFolderAt(token: string, parentPath: string, name: string,
|
||||||
|
siteId: string, libraryId: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const body = {
|
||||||
|
"name": name,
|
||||||
|
"folder": {},
|
||||||
|
"@microsoft.graph.conflictBehavior": "rename"
|
||||||
|
}
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${parentPath}:/children`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async listTemplates(min: GBMinInstance) {
|
||||||
|
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService as any).acquireElevatedToken(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const path = `/`;
|
||||||
|
let res = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return res.value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async copyTemplates(min: GBMinInstance, gbaiDest, templateName: string, kind: string, botName: string) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService as any).acquireElevatedToken(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: gbaiDest.parentReference.driveId, id: gbaiDest.id },
|
||||||
|
"name": `${botName}.${kind}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageName = `${templateName.split('.')[0]}.${kind}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/${templateName}/${packageName}`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${src.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
if (error.code === "itemNotFound") {
|
||||||
|
|
||||||
|
} else if (error.code === "nameAlreadyExists") {
|
||||||
|
|
||||||
|
let src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/${templateName}/${packageName}:/children`)
|
||||||
|
.get();
|
||||||
|
const dstName = `${botName}.gbai/${botName}.${kind}`;
|
||||||
|
let dst = await client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${dstName}`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(src.value, async item => {
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: dst.parentReference.driveId, id: dst.id }
|
||||||
|
}
|
||||||
|
await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${item.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GBLog.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createExcelFile(min: GBMinInstance, destinationFolder: any, name: string) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService.acquireElevatedToken as any)(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: destinationFolder.parentReference.driveId, id: destinationFolder.id },
|
||||||
|
"name": name
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/System.gbdata/blank.xlsx`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${src.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
GBLog.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async shareFolder(token: string, driveId: string, itemId: string, email: string) {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"recipients": [
|
||||||
|
{
|
||||||
|
"email": email
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message": "General Bots Online - Packages folder",
|
||||||
|
"requireSignIn": true,
|
||||||
|
"sendInvitation": true,
|
||||||
|
"roles": ["write"]
|
||||||
|
};
|
||||||
|
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/drives/${driveId}/items/${itemId}/invite`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
GBLog.error('Sharing: ' + err);
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public kmpSearch(pattern, text) {
|
||||||
|
pattern = pattern.toLowerCase();
|
||||||
|
text = text.toLowerCase();
|
||||||
|
if (pattern.length == 0)
|
||||||
|
return 0; // Immediate match
|
||||||
|
|
||||||
|
// Compute longest suffix-prefix table
|
||||||
|
var lsp = [0]; // Base case
|
||||||
|
for (var i = 1; i < pattern.length; i++) {
|
||||||
|
var j = lsp[i - 1]; // Start by assuming we're extending the previous LSP
|
||||||
|
while (j > 0 && pattern.charAt(i) != pattern.charAt(j))
|
||||||
|
j = lsp[j - 1];
|
||||||
|
if (pattern.charAt(i) == pattern.charAt(j))
|
||||||
|
j++;
|
||||||
|
lsp.push(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through text string
|
||||||
|
var j = 0; // Number of chars matched in pattern
|
||||||
|
for (var i = 0; i < text.length; i++) {
|
||||||
|
while (j > 0 && text.charAt(i) != pattern.charAt(j))
|
||||||
|
j = lsp[j - 1]; // Fall back in the pattern
|
||||||
|
if (text.charAt(i) == pattern.charAt(j)) {
|
||||||
|
j++; // Next char matched, increment position
|
||||||
|
if (j == pattern.length)
|
||||||
|
return i - (j - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1; // Not found
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAddressFromZipCode() {
|
||||||
|
// https://maps.googleapis.com/maps/api/geocode/json?address=94040
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrives token and initialize drive client API.
|
||||||
|
*/
|
||||||
|
public static async internalGetDriveClient(min: GBMinInstance) {
|
||||||
|
let token = await (min.adminService as any).acquireElevatedToken(0, true);
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const baseUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}`;
|
||||||
|
return [baseUrl, client];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrives a document from the drive, given a path and filename.
|
||||||
|
*/
|
||||||
|
private async internalGetDocument(client: any, baseUrl: any, path: string, file: string) {
|
||||||
|
let res = await client
|
||||||
|
.api(`${baseUrl}/drive/root:${path}:/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let documents = res.value.filter(m => {
|
||||||
|
return m.name.toLowerCase() === file.toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!documents || documents.length === 0) {
|
||||||
|
throw `File '${file}' specified on GBasic command not found. Check the .gbdata or the .gbdialog associated.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return documents[0];
|
||||||
|
}
|
||||||
|
}
|
579
packages/saas.gbapp/service/JunoSubscription.ts
Executable file
579
packages/saas.gbapp/service/JunoSubscription.ts
Executable file
|
@ -0,0 +1,579 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { HttpMethods, HttpOperationResponse, ServiceClient, WebResource } from '@azure/ms-rest-js';
|
||||||
|
import { GBLog } from 'botlib';
|
||||||
|
import urlJoin from 'url-join';
|
||||||
|
// tslint:disable-next-line: no-require-imports
|
||||||
|
const Juno = require('juno-payment-node');
|
||||||
|
var FormData = require('form-data');
|
||||||
|
export class JunoSubscription {
|
||||||
|
/**
|
||||||
|
* The host this service will call REST API through VPN.
|
||||||
|
*/
|
||||||
|
public host: string = process.env.SAAS_JUNO_HOST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private async getAuthorizationToken(): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Getting Auth Token from API...`);
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = 'POST';
|
||||||
|
req.url = JunoSubscription.getAuthUrl();
|
||||||
|
req.body = 'grant_type=client_credentials';
|
||||||
|
req.headers.set('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
req.headers.set(
|
||||||
|
'Authorization',
|
||||||
|
'Basic ' +
|
||||||
|
new Buffer(JunoSubscription.getClientId() + ':' + JunoSubscription.getClientSecret()).toString('base64')
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from Authorization API ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private async setupWebhook(): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Setting Webhook...`);
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const host = process.env.BOT_URL;
|
||||||
|
const url = `${host}/store.gbapp/payment_notification`;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
url: '',
|
||||||
|
eventTypes: ['PAYMENT_NOTIFICATION']
|
||||||
|
};
|
||||||
|
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = 'POST';
|
||||||
|
req.url = urlJoin(JunoSubscription.getResourceUrl(), 'notifications', 'webhooks');
|
||||||
|
|
||||||
|
req.body = body;
|
||||||
|
req.headers.set('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
req.headers.set(
|
||||||
|
'Authorization',
|
||||||
|
'Basic ' +
|
||||||
|
new Buffer(JunoSubscription.getClientId() + ':' + JunoSubscription.getClientSecret()).toString('base64')
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from Authorization API ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private static createRequestObject(
|
||||||
|
token: string,
|
||||||
|
url: string,
|
||||||
|
verb: HttpMethods,
|
||||||
|
body: string,
|
||||||
|
headers: any,
|
||||||
|
externalAccountToken = undefined
|
||||||
|
): WebResource {
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = verb;
|
||||||
|
req.url = url;
|
||||||
|
|
||||||
|
req.headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||||
|
req.headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
req.headers.set('X-Api-Version', 2);
|
||||||
|
req.headers.set(
|
||||||
|
'X-Resource-Token',
|
||||||
|
externalAccountToken ? externalAccountToken : JunoSubscription.getJunoPrivateKey()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (headers !== undefined) {
|
||||||
|
// tslint:disable-next-line: typedef
|
||||||
|
headers.forEach(e => {
|
||||||
|
req.headers.set(e.name, e.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
req.body = body;
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async PayByBoleto(
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
amount: number
|
||||||
|
): Promise<string> {
|
||||||
|
let charge = await this.createCharge(name, document, email, phone, amount, 'BOLETO');
|
||||||
|
|
||||||
|
return charge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async PayByCC(
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
ccNumber: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string,
|
||||||
|
ccCode: string,
|
||||||
|
amount: number
|
||||||
|
): Promise<string> {
|
||||||
|
let externalSubscriptionId = '1';
|
||||||
|
|
||||||
|
let charge = await this.createCharge(name, document, email, phone, amount, 'CREDIT_CARD');
|
||||||
|
|
||||||
|
let ccHash = await this.getCardHash(ccNumber, name, ccCode, ccExpiresOnMonth, ccExpiresOnYear);
|
||||||
|
let ccId = await this.getCreditCardId(ccHash);
|
||||||
|
let final = await this.makePayment(ccId, ccHash, charge.Id, email);
|
||||||
|
|
||||||
|
return externalSubscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Get active users available to the workflow process.
|
||||||
|
*/
|
||||||
|
public async createDigitalAccount(
|
||||||
|
name,
|
||||||
|
document,
|
||||||
|
email,
|
||||||
|
birthDate,
|
||||||
|
phone,
|
||||||
|
businessArea,
|
||||||
|
linesOfBusiness,
|
||||||
|
number: string,
|
||||||
|
digit: string,
|
||||||
|
bank: string
|
||||||
|
) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createDigitalAccount API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), 'digital-accounts');
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', '', undefined);
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
type: 'PAYMENT',
|
||||||
|
name: name,
|
||||||
|
document: document,
|
||||||
|
email: email,
|
||||||
|
birthDate: birthDate,
|
||||||
|
phone: phone
|
||||||
|
};
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from createDigitalAccount ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createCharge(name, document, email, phone, amount, paymentType) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createCharge API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), 'charges');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
charge: {
|
||||||
|
description: 'string',
|
||||||
|
amount: amount,
|
||||||
|
paymentTypes: [paymentType]
|
||||||
|
},
|
||||||
|
billing: {
|
||||||
|
name: name,
|
||||||
|
document: document,
|
||||||
|
email: email,
|
||||||
|
phone: phone,
|
||||||
|
notify: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createCharge ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.charges[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createPlan(name, amount) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createPlan API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/plans');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
name: name,
|
||||||
|
amount: amount
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createPlan ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createSubscription(
|
||||||
|
dueDay,
|
||||||
|
planId,
|
||||||
|
description,
|
||||||
|
email,
|
||||||
|
creditCardId,
|
||||||
|
creditCardHash,
|
||||||
|
street,
|
||||||
|
number,
|
||||||
|
city,
|
||||||
|
state,
|
||||||
|
postCode,
|
||||||
|
partnerAccountToken
|
||||||
|
) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createSubscription API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/subscriptions');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
dueDay: dueDay,
|
||||||
|
planId: planId,
|
||||||
|
chargeDescription: description,
|
||||||
|
creditCardDetails: {
|
||||||
|
creditCardId: creditCardId,
|
||||||
|
creditCardHash: creditCardHash
|
||||||
|
},
|
||||||
|
billing: {
|
||||||
|
email: email,
|
||||||
|
address: {
|
||||||
|
street: street,
|
||||||
|
number: number,
|
||||||
|
city: city,
|
||||||
|
state: state,
|
||||||
|
postCode: postCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (partnerAccountToken) {
|
||||||
|
json['split'] = [
|
||||||
|
{
|
||||||
|
recipientToken: this.getAuthorizationToken(),
|
||||||
|
percentage: 90,
|
||||||
|
amountRemainder: true,
|
||||||
|
chargeFee: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
recipientToken: partnerAccountToken,
|
||||||
|
percentage: 10,
|
||||||
|
amountRemainder: false,
|
||||||
|
chargeFee: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createSubscription ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBusinessAreas() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getBusinessAreas API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/business-areas');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getBusiness ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.businessAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBanks() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getBanks API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/banks');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getBanks ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCompanyTypes() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getCompanyTypes API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/company-types');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getCompanyTypes ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountPublicKey(externalAccountToken) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountPublicKey API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/credentials/public-key');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountPublicKey ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.bodyAsText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async listAccountDocuments(externalAccountToken: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling listAccountDocuments API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/documents');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from listAccountDocuments ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.documents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountDocumentProperties(externalAccountToken: string, id: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountDocumentProperties API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), `/documents/${id}`);
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountDocumentProperties ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendAccountDocument(externalAccountToken: string, id: string, file: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling sendAccountDocument API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), `/documents/${id}/files`);
|
||||||
|
var form = new FormData();
|
||||||
|
form.append('file', fs.readFileSync(file));
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(
|
||||||
|
token,
|
||||||
|
url,
|
||||||
|
'POST',
|
||||||
|
form.getBuffer(),
|
||||||
|
form.getHeaders(),
|
||||||
|
externalAccountToken
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from sendAccountDocument ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountBalance(externalAccountToken) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountBalance API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/balance');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountBalance ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccount(externalAccountToken: string, id: string): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling Get Digital Accounts API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/digital-accounts');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from Get Digital Accounts ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCreditCardId(ccHash: string): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling tokenizeCreditCard API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/credit-cards/tokenization');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
creditCardHash: ccHash
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from tokenizeCreditCard ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.creditCardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async makePayment(ccId, ccHash, chargeId, email): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling makePayment API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/payments');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
chargeId: chargeId,
|
||||||
|
billing: {
|
||||||
|
email: email
|
||||||
|
// address: {
|
||||||
|
// street: street,
|
||||||
|
// number: number,
|
||||||
|
// complement: complement,
|
||||||
|
// neighborhood: neighborhood,
|
||||||
|
// city: city,
|
||||||
|
// state: state,
|
||||||
|
// postCode: postCode
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
creditCardDetails: {
|
||||||
|
creditCardId: ccId,
|
||||||
|
creditCardHash: ccHash
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from makePayment ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.charges[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static isProd() {
|
||||||
|
return process.env.SAAS_JUNO_IS_PROD === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getClientId() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_CLIENT_ID : process.env.SAAS_JUNO_SANDBOX_CLIENT_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getClientSecret() {
|
||||||
|
return JunoSubscription.isProd()
|
||||||
|
? process.env.SAAS_JUNO_PROD_CLIENT_SECRET
|
||||||
|
: process.env.SAAS_JUNO_SANDBOX_CLIENT_SECRET;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getJunoPublicKey() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_PUBLIC_KEY : process.env.SAAS_JUNO_SANDBOX_PUBLIC_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getJunoPrivateKey() {
|
||||||
|
return JunoSubscription.isProd()
|
||||||
|
? process.env.SAAS_JUNO_PROD_PRIVATE_KEY
|
||||||
|
: process.env.SAAS_JUNO_SANDBOX_PRIVATE_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getResourceUrl() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_RESOURCE : process.env.SAAS_JUNO_SANDBOX_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getAuthUrl() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_AUTH : process.env.SAAS_JUNO_SANDBOX_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCardHash(
|
||||||
|
ccNumber: string,
|
||||||
|
name: string,
|
||||||
|
ccCode: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string
|
||||||
|
): Promise<string> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let tokenJuno = JunoSubscription.getJunoPublicKey();
|
||||||
|
|
||||||
|
let cardData = {
|
||||||
|
cardNumber: ccNumber,
|
||||||
|
holderName: name,
|
||||||
|
securityCode: ccCode,
|
||||||
|
expirationMonth: ccExpiresOnMonth,
|
||||||
|
expirationYear: ccExpiresOnYear
|
||||||
|
};
|
||||||
|
|
||||||
|
let checkout = new Juno.DirectCheckout(tokenJuno, JunoSubscription.isProd());
|
||||||
|
|
||||||
|
checkout.getCardHash(cardData, resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
136
packages/saas.gbapp/service/MSSubscription.ts
Executable file
136
packages/saas.gbapp/service/MSSubscription.ts
Executable file
|
@ -0,0 +1,136 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { MainService } from "./MainService";
|
||||||
|
const request = require('request-promise-native');
|
||||||
|
|
||||||
|
export class MSSubscriptionService {
|
||||||
|
|
||||||
|
public async handleMSHook(req: any, res: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMSSignUp(req: any, res: any) {
|
||||||
|
let token = req.params.token;
|
||||||
|
let url = `https://marketplaceapi.microsoft.com/api/saas/subscriptions/resolve?api-version=2018-08-31`;
|
||||||
|
let options = {
|
||||||
|
uri: url,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'x-ms-marketplace-token': token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let result = await request.get(options);
|
||||||
|
let data = JSON.parse(result);
|
||||||
|
|
||||||
|
const additionalData = {
|
||||||
|
"id": "<guid>", // purchased SaaS subscription ID
|
||||||
|
"subscriptionName": "Contoso Cloud Solution", // SaaS subscription name
|
||||||
|
"offerId": "offer1", // purchased offer ID
|
||||||
|
"planId": "silver", // purchased offer's plan ID
|
||||||
|
"quantity": "20", // number of purchased seats, might be empty if the plan is not per seat
|
||||||
|
"subscription": { // full SaaS subscription details, see Get Subscription APIs response body for full description
|
||||||
|
"id": "<guid>",
|
||||||
|
"publisherId": "contoso",
|
||||||
|
"offerId": "offer1",
|
||||||
|
"name": "Contoso Cloud Solution",
|
||||||
|
"saasSubscriptionStatus": " PendingFulfillmentStart ",
|
||||||
|
"beneficiary": {
|
||||||
|
"emailId": "test@test.com",
|
||||||
|
"objectId": "<guid>",
|
||||||
|
"tenantId": "<guid>",
|
||||||
|
"pid": "<ID of the user>"
|
||||||
|
},
|
||||||
|
"purchaser": {
|
||||||
|
"emailId": "test@test.com",
|
||||||
|
"objectId": "<guid>",
|
||||||
|
"tenantId": "<guid>",
|
||||||
|
"pid": "<ID of the user>"
|
||||||
|
},
|
||||||
|
"planId": "silver",
|
||||||
|
"term": {
|
||||||
|
"termUnit": "P1M",
|
||||||
|
"startDate": "2019 - 05 - 31",
|
||||||
|
"endDate": "2019-06-29",
|
||||||
|
},
|
||||||
|
"isTest": true,
|
||||||
|
"isFreeTrial": false,
|
||||||
|
"allowedCustomerOperations": [
|
||||||
|
"Delete",
|
||||||
|
"Update",
|
||||||
|
"Read"
|
||||||
|
],
|
||||||
|
"sandboxType": "None",
|
||||||
|
"sessionMode": "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = new MainService();
|
||||||
|
service.createSubscriptionMSFT("email", "plan", "offer",
|
||||||
|
Number.parseInt(additionalData.quantity), additionalData);
|
||||||
|
|
||||||
|
url = `https://marketplaceapi.microsoft.com/api/saas/subscriptions/${data.id}?api-version=2018-08-31`;
|
||||||
|
options = {
|
||||||
|
uri: url,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'x-ms-marketplace-token': token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await request.get(options);
|
||||||
|
data = JSON.parse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMSLanding(req: any, res: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Unsubscribe() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Suspend() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Reinstateou() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async ChangePlan() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async ChangeQuantity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Transfer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
214
packages/saas.gbapp/service/MainService.ts
Executable file
214
packages/saas.gbapp/service/MainService.ts
Executable file
|
@ -0,0 +1,214 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { GBOnlineSubscription } from '../model/MainModel.js';
|
||||||
|
import { GBMinInstance, GBLog } from 'botlib';
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
import urlJoin from 'url-join';
|
||||||
|
|
||||||
|
export class MainService {
|
||||||
|
async createSubscriptionMSFT(email: string, plan: string, offer: string, quantity: number, additionalData: any) { }
|
||||||
|
|
||||||
|
async createSubscription(
|
||||||
|
min: GBMinInstance,
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
mobile: string,
|
||||||
|
botName: string,
|
||||||
|
ccNumber: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string,
|
||||||
|
ccCode: string,
|
||||||
|
templateName: string,
|
||||||
|
free: boolean
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Syncs internal subscription management.
|
||||||
|
|
||||||
|
const status = 'Started';
|
||||||
|
const planId = 'default';
|
||||||
|
const quantity = 1;
|
||||||
|
const amount = 0.52;
|
||||||
|
const language = 'en';
|
||||||
|
|
||||||
|
const subscription = await GBOnlineSubscription.create(<GBOnlineSubscription>{
|
||||||
|
instanceId: min.instance.instanceId,
|
||||||
|
isFreeTrial: free,
|
||||||
|
planId: planId,
|
||||||
|
quantity: quantity,
|
||||||
|
status: status,
|
||||||
|
// TODO: lastCCFourDigits: ccNumber...
|
||||||
|
});
|
||||||
|
|
||||||
|
let externalSubscriptionId = null;
|
||||||
|
let service = min.gbappServices['junoSubscription'];
|
||||||
|
|
||||||
|
if (!free) {
|
||||||
|
// if (ccNumber !== undefined) {
|
||||||
|
// // Performs billing management.
|
||||||
|
|
||||||
|
// externalSubscriptionId = await service.PayByCC(
|
||||||
|
// name,
|
||||||
|
// document,
|
||||||
|
// email,
|
||||||
|
// mobile,
|
||||||
|
// ccNumber,
|
||||||
|
// ccExpiresOnMonth,
|
||||||
|
// ccExpiresOnYear,
|
||||||
|
// ccCode,
|
||||||
|
// amount
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// externalSubscriptionId = await service.PayByBoleto(name, document, email, mobile);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a bot.
|
||||||
|
|
||||||
|
GBLog.info( 'Deploying a blank bot to storage...');
|
||||||
|
|
||||||
|
const instance = await min.deployService.deployBlankBot(botName, mobile, email);
|
||||||
|
|
||||||
|
GBLog.info( 'Creating subscription...');
|
||||||
|
subscription.instanceId = instance.instanceId;
|
||||||
|
subscription.externalSubscriptionId = externalSubscriptionId;
|
||||||
|
await subscription.save();
|
||||||
|
|
||||||
|
let token = await (min.adminService.acquireElevatedToken as any)(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
|
||||||
|
let sleep = ms => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GBLog.info( 'Creating .gbai folder ...');
|
||||||
|
let item = await gboService.createSubFolderAtRoot(token, `${botName}.gbai`, siteId, libraryId);
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
GBLog.info( 'Copying Templates...');
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbkb', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbot', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbtheme', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbdialog', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbdata', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbkb', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbot', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbtheme', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdata', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdialog', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdrive', botName);
|
||||||
|
|
||||||
|
await sleep(10000);
|
||||||
|
GBLog.info( 'Configuring .gbot...');
|
||||||
|
await min.core['setConfig'] (min, instance.botId, "Can Publish", mobile + ";");
|
||||||
|
await min.core['setConfig'](min, instance.botId, "Admin Notify E-mail", email);
|
||||||
|
await min.core['setConfig'](min, instance.botId, 'WebDav Username', instance.botId);
|
||||||
|
await min.core['setConfig'](min, instance.botId, 'WebDav Secret', instance.adminPass);
|
||||||
|
|
||||||
|
GBLog.info( 'Bot creation done.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async otherTasks(min, botName, webUrl, instance, language){
|
||||||
|
let message = `Seu bot ${botName} está disponível no endereço:
|
||||||
|
<br/><a href="${urlJoin(process.env.BOT_URL, botName)}">${urlJoin(process.env.BOT_URL, botName)}</a>.
|
||||||
|
<br/>
|
||||||
|
<br/>Os pacotes do General Bots (ex: .gbkb, .gbtheme) para seu Bot devem ser editados no repositório de pacotes:
|
||||||
|
<br/>
|
||||||
|
<br/><a href="${webUrl}">${webUrl}</a>.
|
||||||
|
<br/>
|
||||||
|
<br/> Digite /publish do seu WhatsApp para publicar os pacotes. Seu número está autorizado na pasta ${botName}.gbot/Config.xlsx
|
||||||
|
<br/>
|
||||||
|
<br/> Guarde a senha raiz: <b>${instance.adminPass}</b> em um local seguro, use-a para realizar o /publish via Web (WhatsApp dispensa senha).
|
||||||
|
<br/>
|
||||||
|
<br/>O arquivo .zip em anexo pode ser importado no Teams conforme instruções em:
|
||||||
|
<br/><a href="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload">https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload</a>.
|
||||||
|
<br/>
|
||||||
|
<br/>Log in to the Teams client with your Microsoft 365 account.
|
||||||
|
<br/>Select Apps and choose Upload a custom app.
|
||||||
|
<br/>Select this .zip file attached to this e-mail. An install dialog displays.
|
||||||
|
<br/>Add your Bot to Teams.
|
||||||
|
<br/>
|
||||||
|
<br/>Atenciosamente,
|
||||||
|
<br/>General Bots Online.
|
||||||
|
<br/><a href="https://gb.pragmatismo.cloud">https://gb.pragmatismo.cloud</a>
|
||||||
|
<br/>
|
||||||
|
<br/>E-mail remetido por Pragmatismo.
|
||||||
|
<br/>`;
|
||||||
|
|
||||||
|
message = await min.conversationalService.translate(
|
||||||
|
min,
|
||||||
|
message,
|
||||||
|
language
|
||||||
|
);
|
||||||
|
|
||||||
|
GBLog.info( 'Generating MS Teams manifest....');
|
||||||
|
|
||||||
|
const appManifest = await min.deployService.getBotManifest(min.instance);
|
||||||
|
|
||||||
|
// GBLog.info( 'Sending e-mails....');
|
||||||
|
// const emailToken = process.env.SAAS_SENDGRID_API_KEY;
|
||||||
|
// gboService.sendEmail(
|
||||||
|
// emailToken,
|
||||||
|
// email,
|
||||||
|
// 'operations@pragmatismo.cloud',
|
||||||
|
// `${botName}`,
|
||||||
|
// message,
|
||||||
|
// message,
|
||||||
|
// {
|
||||||
|
// content: appManifest,
|
||||||
|
// filename: `${min.instance.botId}-Teams.zip`,
|
||||||
|
// type: `application/zip`,
|
||||||
|
// disposition: "attachment"
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const contacts = process.env.SECURITY_LIST.split(';');
|
||||||
|
|
||||||
|
// TODO: await CollectionUtil.asyncForEach(contacts, async item => {
|
||||||
|
// await (min.whatsAppDirectLine as any)['sendToDevice'](
|
||||||
|
// item,
|
||||||
|
// `Novo bot criado agora: http://gb.pragmatismo.cloud/${botName} para *${name}* (${email}, ${mobile}). Por favor, entre em contato para que mais um bot seja configurado adequadamente. `
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// GBLog.info( 'Sharing .gbai folder...');
|
||||||
|
// await gboService.shareFolder(token, item.parentReference.driveId, item.id, email);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
35
packages/saas.gbapp/strings.ts
Executable file
35
packages/saas.gbapp/strings.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
export const Messages = {
|
||||||
|
'en-US': {
|
||||||
|
bot_created: address => `Your bot has been created and it's available at: ${address}`,
|
||||||
|
new_password: newPassword => `Your new password is: **${newPassword}**.`,
|
||||||
|
ok_get_information: 'OK, I will get some information.',
|
||||||
|
ok_procceding_creation: 'I have all that I need to create your Bot. Wait a moment...',
|
||||||
|
own_voucher:
|
||||||
|
'Got a voucher?',
|
||||||
|
please_use_code: code => `Please, answer the Bot with the code: ${code}.`,
|
||||||
|
validation_enter_valid_botname: 'Please enter a valid Bot Name.',
|
||||||
|
validation_enter_valid_voucher: 'Please enter a valid voucher code.',
|
||||||
|
welcome:
|
||||||
|
"Welcome and let's create your Bot. Also visit: https://gb.pragmatismo.cloud/privacy.html to learn more about our privacy policy.",
|
||||||
|
whats_botname: "What's the Bot name?",
|
||||||
|
thanks_payment: 'Thanks for choosing paying for General Bots.',
|
||||||
|
boleto_mail: 'Boleto will be e-mailed to you.'
|
||||||
|
},
|
||||||
|
'pt-BR': {
|
||||||
|
bot_created: address =>
|
||||||
|
`Em alguns minutos seu Bot estará disponível no endereço: ${address}. Você receberá por e-mail, a notificação da criação. Entraremos em contato em até 1(um) dia útil para realizar a configuração final.`,
|
||||||
|
new_password: newPassword => `Sua nova senha é: **${newPassword}**.`,
|
||||||
|
ok_get_information: 'OK, vou solicitar algumas informações.',
|
||||||
|
ok_procceding_creation: 'Tenho tudo que preciso para criar seu Bot, só um instante...',
|
||||||
|
own_voucher: 'Tem um voucher algo como GB2020 ou não?',
|
||||||
|
please_use_code: code => `Por favor, responda ao bot com o código: ${code}.`,
|
||||||
|
validation_enter_valid_botname:
|
||||||
|
'Por favor, digite um nome de Bot válido, usando apenas letras maiúsculas e minúsculas sem espaços ou outros caracteres.',
|
||||||
|
validation_enter_valid_voucher: 'Por favor, digite um código de voucher válido.',
|
||||||
|
welcome:
|
||||||
|
'Bem-vinda(o) e vamos criar seu bot. Visite também: https://gb.pragmatismo.cloud/privacy.html para conhecer nossa política de privacidade',
|
||||||
|
whats_botname: 'Qual é o nome do *Bot*? (Apenas letras maiúsculas e minúsculas, sem espaços ou demais caracteres)',
|
||||||
|
thanks_payment: 'Gratidão por escolher o plano pago do General Bots.',
|
||||||
|
boleto_mail: 'Boleto será enviado por e-mail.'
|
||||||
|
}
|
||||||
|
};
|
20
packages/saas.gbapp/test/subscription.ts
Normal file
20
packages/saas.gbapp/test/subscription.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// TODO: TEST.
|
||||||
|
|
||||||
|
// const service = new MainService();
|
||||||
|
// await service.createSubscription(
|
||||||
|
// min,
|
||||||
|
// 'Test',
|
||||||
|
// '999999999999',
|
||||||
|
// '@domain.cloud',
|
||||||
|
// '9999999999999',
|
||||||
|
// 'bot'+min.adminService['getRndReadableIdentifier'](),
|
||||||
|
// null,
|
||||||
|
// '11',
|
||||||
|
// '22',
|
||||||
|
// '333',
|
||||||
|
// 'Starter.gbai',
|
||||||
|
// true
|
||||||
|
// );
|
||||||
|
// step.endDialog();
|
||||||
|
// return;
|
||||||
|
|
Loading…
Add table
Reference in a new issue