354 lines
12 KiB
TypeScript
Executable file
354 lines
12 KiB
TypeScript
Executable file
/*****************************************************************************\
|
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
|
| |
|
|
| 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];
|
|
}
|
|
}
|