botserver/packages/saas.gbapp/service/MainService.ts
Rodrigo Rodriguez (Pragmatismo) bc0aa7627e
Some checks failed
GBCI / build (push) Failing after 3m57s
feat: update dependencies and improve file handling in GBVMService
2025-04-18 22:20:33 -03:00

260 lines
10 KiB
TypeScript
Executable file

/*****************************************************************************\
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
| |
| General Bots Copyright (c) pragmatismo.com.br. 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.com.br. |
| 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';
import { GBOService } from './GBOService.js';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js';
import Stripe from 'stripe';
export class MainService {
private stripe: Stripe;
constructor() {
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
}
async createStripeCustomer(name: string, email: string, paymentMethodId: string) {
const customer = await this.stripe.customers.create({
name,
email,
payment_method: paymentMethodId,
invoice_settings: {
default_payment_method: paymentMethodId
}
});
return customer;
}
async createStripeSubscription(customerId: string, priceId: string) {
const subscription = await this.stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
expand: ['latest_invoice.payment_intent']
});
return subscription;
}
async createPaymentMethod(cardNumber: string, expMonth: number, expYear: number, cvc: string) {
const paymentMethod = await this.stripe.paymentMethods.create({
type: 'card',
card: {
number: cardNumber,
exp_month: expMonth,
exp_year: expYear,
cvc: cvc
}
}, {});
return paymentMethod;
}
async createSubscription(
min: GBMinInstance,
name: string,
document: string,
email: string,
mobile: string,
botName: string,
ccNumber: string,
ccExpiresOnMonth: number,
ccExpiresOnYear: number,
ccCode: string,
templateName: string,
free: boolean, planId: string,
) {
let externalSubscriptionId = null;
if (!free) {
try {
// Create Stripe payment method
const paymentMethod = await this.createPaymentMethod(
ccNumber,
ccExpiresOnMonth,
ccExpiresOnYear,
ccCode
);
// Create Stripe customer
const customer = await this.createStripeCustomer(
name,
email,
paymentMethod.id
);
// Determine price ID based on plan
const priceId = planId === 'professional'
? process.env.STRIPE_PROFESSIONAL_PRICE_ID
: process.env.STRIPE_PERSONAL_PRICE_ID;
// Create subscription
const subscription = await this.createStripeSubscription(
customer.id,
priceId
);
externalSubscriptionId = subscription.id;
} catch (error) {
GBLog.error(`Stripe payment failed: ${error.message}`);
throw error;
}
}
// Syncs internal subscription management
const status = free ? 'FreeTrial' : 'Active';
GBLog.info(`Creating subscription for ${name} (${email}, ${mobile}) with status: ${status}`);
const quantity = 1;
const amount = 1;
const subscription = await GBOnlineSubscription.create({
instanceId: min.instance.instanceId,
isFreeTrial: free,
planId: planId,
quantity: quantity,
status: status,
amount: amount,
lastCCFourDigits: ccNumber ? ccNumber.slice(-4) : null
});
// 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 =
GBConfigService.get('GB_MODE') === 'legacy' ?
await (min.adminService.acquireElevatedToken as any)(min.instance.instanceId, true) :
null;
let siteId = process.env.STORAGE_SITE_ID;
let libraryId = process.env.STORAGE_LIBRARY;
let gboService = new GBOService();
let sleep = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};
GBLog.info('Creating .gbai folder ...');
let item = await gboService.createRootFolder(token, `${botName}.gbai`, siteId, libraryId);
GBLog.info('Copying Templates...');
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/>
<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=""></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,
// `${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.com.br/${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);
}
}