From 4d96286cc2e8f648ebd01193672b66e55efbbc95 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 26 Oct 2023 13:39:10 +0330 Subject: [PATCH 1/6] Revert "Revert "Continue JS -> TS conversion (#435)" (#440)" This reverts commit 62fd089b091953a1c4b547e4bdd197cac493af5d. --- app.js => app.ts | 19 ++- bot/messages.ts | 14 +- bot/start.ts | 62 ++++---- bot/{validations.js => validations.ts} | 125 +++++++++------ db_connect.js => db_connect.ts | 8 +- ...ngs.js => calculate_community_earnings.ts} | 13 +- jobs/{cancel_orders.js => cancel_orders.ts} | 19 ++- jobs/{communities.js => communities.ts} | 15 +- ...d_orders.js => delete_published_orders.ts} | 15 +- jobs/index.js | 19 --- jobs/index.ts | 19 +++ jobs/{node_info.js => node_info.ts} | 14 +- jobs/pending_payments.ts | 27 ++-- ln/{connect.js => connect.ts} | 10 +- ln/{hold_invoice.js => hold_invoice.ts} | 24 +-- ln/{index.js => index.ts} | 14 +- ln/info.js | 13 -- ln/info.ts | 11 ++ ...be_invoices.js => resubscribe_invoices.ts} | 18 ++- ...scribe_invoice.js => subscribe_invoice.ts} | 22 ++- lnurl/{lnurl-pay.js => lnurl-pay.ts} | 15 +- logger.js => logger.ts | 10 +- models/community.ts | 2 +- models/config.ts | 3 +- models/dispute.ts | 2 +- models/index.js | 15 -- models/index.ts | 15 ++ models/order.ts | 2 +- models/pending_payment.ts | 2 +- models/user.ts | 2 +- package-lock.json | 42 +++++- package.json | 2 + tests/bot_test.js | 2 +- tsconfig.json | 3 + util/fiatModel.ts | 4 + util/{index.js => index.ts} | 142 ++++++++++-------- util/languagesModel.ts | 9 ++ 37 files changed, 441 insertions(+), 312 deletions(-) rename app.js => app.ts (62%) rename bot/{validations.js => validations.ts} (75%) rename db_connect.js => db_connect.ts (81%) rename jobs/{calculate_community_earnings.js => calculate_community_earnings.ts} (78%) rename jobs/{cancel_orders.js => cancel_orders.ts} (85%) rename jobs/{communities.js => communities.ts} (70%) rename jobs/{delete_published_orders.js => delete_published_orders.ts} (73%) delete mode 100644 jobs/index.js create mode 100644 jobs/index.ts rename jobs/{node_info.js => node_info.ts} (51%) rename ln/{connect.js => connect.ts} (89%) rename ln/{hold_invoice.js => hold_invoice.ts} (61%) rename ln/{index.js => index.ts} (64%) delete mode 100644 ln/info.js create mode 100644 ln/info.ts rename ln/{resubscribe_invoices.js => resubscribe_invoices.ts} (65%) rename ln/{subscribe_invoice.js => subscribe_invoice.ts} (82%) rename lnurl/{lnurl-pay.js => lnurl-pay.ts} (77%) rename logger.js => logger.ts (82%) delete mode 100644 models/index.js create mode 100644 models/index.ts rename util/{index.js => index.ts} (73%) create mode 100644 util/languagesModel.ts diff --git a/app.js b/app.ts similarity index 62% rename from app.js rename to app.ts index 2fbc6604..1809beec 100644 --- a/app.js +++ b/app.ts @@ -1,9 +1,11 @@ -require('dotenv').config(); -const { SocksProxyAgent } = require('socks-proxy-agent'); -const { start } = require('./bot'); -const mongoConnect = require('./db_connect'); +import * as dotenv from "dotenv"; +dotenv.config() +import { SocksProxyAgent } from "socks-proxy-agent"; +import { MainContext, start } from "./bot/start"; +import mongoConnect from './db_connect' const { resubscribeInvoices } = require('./ln'); -const logger = require('./logger'); +import logger from "./logger"; +import { Telegraf } from "telegraf"; const { delay } = require('./util'); (async () => { @@ -23,7 +25,7 @@ const { delay } = require('./util'); mongoose.connection .once('open', async () => { logger.info('Connected to Mongo instance.'); - let options = { handlerTimeout: 60000 }; + let options: Partial> = { handlerTimeout: 60000 }; if (process.env.SOCKS_PROXY_HOST) { const agent = new SocksProxyAgent(process.env.SOCKS_PROXY_HOST); options = { @@ -32,10 +34,11 @@ const { delay } = require('./util'); }, }; } - const bot = start(process.env.BOT_TOKEN, options); + const bot = start(String(process.env.BOT_TOKEN), options); // Wait 1 seconds before try to resubscribe hold invoices await delay(1000); await resubscribeInvoices(bot); }) - .on('error', error => logger.error(`Error connecting to Mongo: ${error}`)); + .on('error', (error: Error) => logger.error(`Error connecting to Mongo: ${error}`)); })(); + diff --git a/bot/messages.ts b/bot/messages.ts index 8bdf299c..a49ccac7 100644 --- a/bot/messages.ts +++ b/bot/messages.ts @@ -1,5 +1,5 @@ -const { TelegramError } = require('telegraf'); -const QR = require('qrcode'); +import { TelegramError } from 'telegraf' +import QR from 'qrcode'; const { getCurrency, numberFormat, @@ -12,7 +12,7 @@ const { decimalRound, getUserAge, } = require('../util'); -const logger = require('../logger'); +import logger from "../logger"; import { MainContext } from './start'; import { UserDocument } from '../models/user' import { IOrder } from '../models/order' @@ -109,7 +109,7 @@ const invoicePaymentRequestMessage = async ( } }; -const pendingSellMessage = async (ctx: MainContext, user: UserDocument, order: IOrder, channel: string, i18n: I18nContext) => { +const pendingSellMessage = async (ctx: Telegraf, user: UserDocument, order: IOrder, channel: string, i18n: I18nContext) => { try { const orderExpirationWindow = Number(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW) / 60 / 60; @@ -618,7 +618,7 @@ const publishBuyOrderMessage = async ( }; const publishSellOrderMessage = async ( - ctx: MainContext, + ctx: Telegraf, user: UserDocument, order: IOrder, i18n: I18nContext, @@ -1549,7 +1549,7 @@ const currencyNotSupportedMessage = async (ctx: MainContext, currencies: Array { +const notAuthorized = async (ctx: MainContext, tgId?: string) => { try { if (tgId) { await ctx.telegram.sendMessage(tgId, ctx.i18n.t('not_authorized')); @@ -1606,7 +1606,7 @@ const showConfirmationButtons = async (ctx: MainContext, orders: Array, } }; -module.exports = { +export { startMessage, initBotErrorMessage, invoicePaymentRequestMessage, diff --git a/bot/start.ts b/bot/start.ts index a3e2ff5e..7546081a 100644 --- a/bot/start.ts +++ b/bot/start.ts @@ -3,17 +3,16 @@ import { I18n, I18nContext } from '@grammyjs/i18n'; import { Message } from 'typegram' import { UserDocument } from '../models/user' import { FilterQuery } from 'mongoose'; - -const { limit } = require('@grammyjs/ratelimiter'); -const schedule = require('node-schedule'); -const { +import { limit } from "@grammyjs/ratelimiter" +import schedule from 'node-schedule'; +import { Order, User, PendingPayment, Community, Dispute, Config, -} = require('../models'); +} from '../models'; const { getCurrenciesWithPrice, deleteOrderFromChannel } = require('../util'); const { commandArgsMiddleware, @@ -56,7 +55,7 @@ const { validateInvoice, validateLightningAddress, } = require('./validations'); -const messages = require('./messages'); +import * as messages from './messages'; const { attemptPendingPayments, cancelOrders, @@ -66,7 +65,8 @@ const { deleteCommunity, nodeInfo, } = require('../jobs'); -const logger = require('../logger'); +import logger from "../logger"; +import { ICommunity, IUsernameId } from '../models/community'; export interface MainContext extends Context { match: Array | null; @@ -75,7 +75,7 @@ export interface MainContext extends Context { admin: UserDocument; } -interface OrderQuery { +export interface OrderQuery { status?: string; buyer_id?: string; seller_id?: string; @@ -125,6 +125,7 @@ const askForConfirmation = async (user: UserDocument, command: string) => { return []; } catch (error) { logger.error(error); + return null; } }; @@ -137,7 +138,7 @@ has the same condition. The problem mentioned above is similar to this issue: https://github.com/telegraf/telegraf/issues/1319#issuecomment-766360594 */ -const ctxUpdateAssertMsg = "ctx.update.message.text is not available."; +export const ctxUpdateAssertMsg = "ctx.update.message.text is not available."; const initialize = (botToken: string, options: Partial>): Telegraf => { const i18n = new I18n({ @@ -209,7 +210,7 @@ const initialize = (botToken: string, options: Partial'); if (!val) return; let config = await Config.findOne(); - if (!config) { + if (config === null) { config = new Config(); } config.maintenance = false; @@ -256,11 +257,11 @@ const initialize = (botToken: string, options: Partial el); + const [command, orderId] = params.filter((el: string) => el); if (!orderId) { const orders = await askForConfirmation(ctx.user, command); - if (!orders.length) return await ctx.reply(`${command} `); + if (orders === null || orders.length === 0) return await ctx.reply(`${command} `); return await messages.showConfirmationButtons(ctx, orders, command); } else if (!(await validateObjectId(ctx, orderId))) { @@ -283,7 +284,7 @@ const initialize = (botToken: string, options: Partial el); + const [command, orderId] = params.filter((el: string) => el); if (!orderId) { const orders = await askForConfirmation(ctx.user, command); - if (!orders.length) return await ctx.reply(`${command} `); + if (orders === null || orders.length === 0) return await ctx.reply(`${command} `); return await messages.showConfirmationButtons(ctx, orders, command); } else if (!(await validateObjectId(ctx, orderId))) { @@ -394,7 +396,7 @@ const initialize = (botToken: string, options: Partial el); + const [command, orderId] = params.filter((el: string) => el); if (!orderId) { const orders = await askForConfirmation(ctx.user, command); - if (!orders.length) return await ctx.reply(`${command} `); + if (orders === null || orders.length === 0) return await ctx.reply(`${command} `); return await messages.showConfirmationButtons(ctx, orders, command); } else if (!(await validateObjectId(ctx, orderId))) { @@ -554,7 +557,7 @@ const initialize = (botToken: string, options: Partial el.id !== user.id + if (community === null) throw Error("Community was not found in DB"); + community.banned_users = community.banned_users.toObject().filter( + (el: IUsernameId) => el.id !== user.id ); await community.save(); } else { @@ -821,6 +826,7 @@ const initialize = (botToken: string, options: Partial { try { const config = await Config.findOne({}); + if (config === null) throw Error("Config was not found in DB"); await messages.showInfoMessage(ctx, ctx.user, config); } catch (error) { logger.error(error); diff --git a/bot/validations.js b/bot/validations.ts similarity index 75% rename from bot/validations.js rename to bot/validations.ts index a3288bd2..e6ce3881 100644 --- a/bot/validations.js +++ b/bot/validations.ts @@ -1,18 +1,32 @@ +import { MainContext, OrderQuery, ctxUpdateAssertMsg } from "./start"; +import { ICommunity } from "../models/community"; +import { FilterQuery } from "mongoose"; +import { UserDocument } from "../models/user"; +import { IOrder } from "../models/order"; +import { Telegraf } from "telegraf"; + const { parsePaymentRequest } = require('invoices'); const { ObjectId } = require('mongoose').Types; -const messages = require('./messages'); -const { Order, User, Community } = require('../models'); +import * as messages from './messages'; +import { Order, User, Community } from '../models'; const { isIso4217, isDisputeSolver } = require('../util'); const { existLightningAddress } = require('../lnurl/lnurl-pay'); const logger = require('../logger'); // We look in database if the telegram user exists, // if not, it creates a new user -const validateUser = async (ctx, start) => { +const validateUser = async (ctx: MainContext, start: boolean) => { try { - const tgUser = ctx.update.callback_query - ? ctx.update.callback_query.from - : ctx.update.message.from; + let tgUser = null; + if (("callback_query" in ctx.update) && ctx.update.callback_query) { + tgUser = ctx.update.callback_query.from; + } + else if (("message" in ctx.update) && ctx.update.message) { + tgUser = ctx.update.message.from; + } + else { + throw new Error(ctxUpdateAssertMsg); + } // We need to make sure the user has a username if (!tgUser.username) { return await messages.nonHandleErrorMessage(ctx); @@ -45,15 +59,18 @@ const validateUser = async (ctx, start) => { } }; -const validateSuperAdmin = async (ctx, id) => { +const validateSuperAdmin = async (ctx: MainContext, id?: string) => { try { + if (!('message' in ctx.update) || !('text' in ctx.update.message)) { + throw new Error(ctxUpdateAssertMsg); + } const tgUserId = id || ctx.update.message.from.id; const user = await User.findOne({ tg_id: tgUserId }); // If the user never started the bot we can't send messages // to that user, so we do nothing - if (!user) return; + if (user === null) return; - if (!user.admin) return await messages.notAuthorized(ctx, tgUserId); + if (!user.admin) return await messages.notAuthorized(ctx, tgUserId.toString()); return user; } catch (error) { @@ -62,22 +79,26 @@ const validateSuperAdmin = async (ctx, id) => { } }; -const validateAdmin = async (ctx, id) => { +const validateAdmin = async (ctx: MainContext, id?: string) => { try { + if (!('message' in ctx.update) || !('text' in ctx.update.message)) { + throw new Error(ctxUpdateAssertMsg); + } const tgUserId = id || ctx.update.message.from.id; const user = await User.findOne({ tg_id: tgUserId }); // If the user never started the bot we can't send messages // to that user, so we do nothing - if (!user) return; + if (user === null) return; let community = null; if (user.default_community_id) community = await Community.findOne({ _id: user.default_community_id }); + if (community === null) throw Error("Community was not found in DB"); const isSolver = isDisputeSolver(community, user); if (!user.admin && !isSolver) - return await messages.notAuthorized(ctx, tgUserId); + return await messages.notAuthorized(ctx, tgUserId.toString()); return user; } catch (error) { @@ -86,7 +107,7 @@ const validateAdmin = async (ctx, id) => { } }; -const validateSellOrder = async ctx => { +const validateSellOrder = async (ctx: MainContext) => { try { const args = ctx.state.command.args; if (args.length < 4) { @@ -130,11 +151,11 @@ const validateSellOrder = async ctx => { return false; } - if (amount !== 0 && amount < process.env.MIN_PAYMENT_AMT) { + if (amount !== 0 && amount < Number(process.env.MIN_PAYMENT_AMT)) { await messages.mustBeGreatherEqThan( ctx, 'monto_en_sats', - process.env.MIN_PAYMENT_AMT + Number(process.env.MIN_PAYMENT_AMT) ); return false; } @@ -149,7 +170,7 @@ const validateSellOrder = async ctx => { return false; } - if (fiatAmount.some(x => x < 1)) { + if (fiatAmount.some((x: number) => x < 1)) { await messages.mustBeGreatherEqThan(ctx, 'monto_en_fiat', 1); return false; } @@ -174,7 +195,7 @@ const validateSellOrder = async ctx => { } }; -const validateBuyOrder = async ctx => { +const validateBuyOrder = async (ctx: MainContext) => { try { const args = ctx.state.command.args; if (args.length < 4) { @@ -216,11 +237,11 @@ const validateBuyOrder = async ctx => { return false; } - if (amount !== 0 && amount < process.env.MIN_PAYMENT_AMT) { + if (amount !== 0 && amount < Number(process.env.MIN_PAYMENT_AMT)) { await messages.mustBeGreatherEqThan( ctx, 'monto_en_sats', - process.env.MIN_PAYMENT_AMT + Number(process.env.MIN_PAYMENT_AMT) ); return false; } @@ -235,7 +256,7 @@ const validateBuyOrder = async ctx => { return false; } - if (fiatAmount.some(x => x < 1)) { + if (fiatAmount.some((x: number) => x < 1)) { await messages.mustBeGreatherEqThan(ctx, 'monto_en_fiat', 1); return false; } @@ -259,7 +280,7 @@ const validateBuyOrder = async ctx => { return false; } }; -const validateLightningAddress = async lightningAddress => { +const validateLightningAddress = async (lightningAddress: string) => { const pattern = /^[\w-.]+@([\w-]+.)+[\w-]{2,4}$/g; return ( @@ -267,18 +288,19 @@ const validateLightningAddress = async lightningAddress => { ); }; -const validateInvoice = async (ctx, lnInvoice) => { +const validateInvoice = async (ctx: MainContext, lnInvoice: string) => { try { const invoice = parsePaymentRequest({ request: lnInvoice }); const latestDate = new Date( - Date.now() + parseInt(process.env.INVOICE_EXPIRATION_WINDOW) + Date.now() + Number(process.env.INVOICE_EXPIRATION_WINDOW) ).toISOString(); - if (!!invoice.tokens && invoice.tokens < process.env.MIN_PAYMENT_AMT) { + if (!("MAIN_PAYMENT_AMT" in process.env)) throw Error("MIN_PAYMENT_AMT not found, please check .env file"); + if (!!invoice.tokens && invoice.tokens < Number(process.env.MIN_PAYMENT_AMT)) { await messages.minimunAmountInvoiceMessage(ctx); return false; } - if (new Date(invoice.expires_at) < latestDate) { + if (new Date(invoice.expires_at).toISOString() < latestDate) { await messages.minimunExpirationTimeInvoiceMessage(ctx); return false; } @@ -306,20 +328,20 @@ const validateInvoice = async (ctx, lnInvoice) => { } }; -const isValidInvoice = async (ctx, lnInvoice) => { +const isValidInvoice = async (ctx: MainContext, lnInvoice: string) => { try { const invoice = parsePaymentRequest({ request: lnInvoice }); const latestDate = new Date( - Date.now() + parseInt(process.env.INVOICE_EXPIRATION_WINDOW) + Date.now() + Number(process.env.INVOICE_EXPIRATION_WINDOW) ).toISOString(); - if (!!invoice.tokens && invoice.tokens < process.env.MIN_PAYMENT_AMT) { + if (!!invoice.tokens && invoice.tokens < Number(process.env.MIN_PAYMENT_AMT)) { await messages.invoiceMustBeLargerMessage(ctx); return { success: false, }; } - if (new Date(invoice.expires_at) < latestDate) { + if (new Date(invoice.expires_at).toISOString() < latestDate) { await messages.invoiceExpiryTooShortMessage(ctx); return { success: false, @@ -359,7 +381,7 @@ const isValidInvoice = async (ctx, lnInvoice) => { } }; -const isOrderCreator = (user, order) => { +const isOrderCreator = (user: UserDocument, order: IOrder) => { try { return user._id == order.creator_id; } catch (error) { @@ -368,7 +390,7 @@ const isOrderCreator = (user, order) => { } }; -const validateTakeSellOrder = async (ctx, bot, user, order) => { +const validateTakeSellOrder = async (ctx: MainContext, bot: Telegraf, user: UserDocument, order: IOrder) => { try { if (!order) { await messages.invalidOrderMessage(ctx, bot, user); @@ -397,10 +419,10 @@ const validateTakeSellOrder = async (ctx, bot, user, order) => { } }; -const validateTakeBuyOrder = async (ctx, bot, user, order) => { +const validateTakeBuyOrder = async (ctx: MainContext, bot: Telegraf, user: UserDocument, order: IOrder) => { try { if (!order) { - await messages.invalidOrderMessage(bot, user); + await messages.invalidOrderMessage(ctx, bot, user); return false; } if (isOrderCreator(user, order) && process.env.NODE_ENV === 'production') { @@ -422,9 +444,9 @@ const validateTakeBuyOrder = async (ctx, bot, user, order) => { } }; -const validateReleaseOrder = async (ctx, user, orderId) => { +const validateReleaseOrder = async (ctx: MainContext, user: UserDocument, orderId: string) => { try { - let where = { + let where: FilterQuery = { seller_id: user._id, status: 'WAITING_BUYER_INVOICE', _id: orderId, @@ -453,7 +475,7 @@ const validateReleaseOrder = async (ctx, user, orderId) => { } order = await Order.findOne(where); - if (!order) { + if (order === null) { await messages.notActiveOrderMessage(ctx); return false; } @@ -465,7 +487,7 @@ const validateReleaseOrder = async (ctx, user, orderId) => { } }; -const validateDisputeOrder = async (ctx, user, orderId) => { +const validateDisputeOrder = async (ctx: MainContext, user: UserDocument, orderId: string) => { try { const where = { $and: [ @@ -477,7 +499,7 @@ const validateDisputeOrder = async (ctx, user, orderId) => { const order = await Order.findOne(where); - if (!order) { + if (order === null) { await messages.notActiveOrderMessage(ctx); return false; } @@ -489,9 +511,9 @@ const validateDisputeOrder = async (ctx, user, orderId) => { } }; -const validateFiatSentOrder = async (ctx, user, orderId) => { +const validateFiatSentOrder = async (ctx: MainContext, user: UserDocument, orderId: string) => { try { - const where = { + const where: FilterQuery = { $and: [ { buyer_id: user._id }, { $or: [{ status: 'ACTIVE' }, { status: 'PAID_HOLD_INVOICE' }] }, @@ -502,7 +524,7 @@ const validateFiatSentOrder = async (ctx, user, orderId) => { where._id = orderId; } const order = await Order.findOne(where); - if (!order) { + if (order === null) { await messages.notActiveOrderMessage(ctx); return false; } @@ -525,7 +547,7 @@ const validateFiatSentOrder = async (ctx, user, orderId) => { }; // If a seller have an order with status FIAT_SENT, return false -const validateSeller = async (ctx, user) => { +const validateSeller = async (ctx: MainContext, user: UserDocument) => { try { const where = { seller_id: user._id, @@ -546,10 +568,13 @@ const validateSeller = async (ctx, user) => { } }; -const validateParams = async (ctx, paramNumber, errOutputString) => { +const validateParams = async (ctx: MainContext, paramNumber: number, errOutputString: string): Promise> => { try { + if (!('message' in ctx.update) || !('text' in ctx.update.message)) { + throw new Error(ctxUpdateAssertMsg); + } const paramsArray = ctx.update.message.text.split(' '); - const params = paramsArray.filter(el => el !== ''); + const params = paramsArray.filter((el: string) => el !== ''); if (params.length !== paramNumber) { await messages.customMessage( ctx, @@ -562,11 +587,11 @@ const validateParams = async (ctx, paramNumber, errOutputString) => { return params.slice(1); } catch (error) { logger.error(error); - return false; + return null; } }; -const validateObjectId = async (ctx, id) => { +const validateObjectId = async (ctx: MainContext, id: string) => { try { if (!ObjectId.isValid(id)) { await messages.notValidIdMessage(ctx); @@ -580,10 +605,10 @@ const validateObjectId = async (ctx, id) => { } }; -const validateUserWaitingOrder = async (ctx, bot, user) => { +const validateUserWaitingOrder = async (ctx: MainContext, bot: Telegraf, user: UserDocument) => { try { // If is a seller - let where = { + let where: FilterQuery = { seller_id: user._id, status: 'WAITING_PAYMENT', }; @@ -610,12 +635,12 @@ const validateUserWaitingOrder = async (ctx, bot, user) => { }; // We check if the user is banned from the community in the order -const isBannedFromCommunity = async (user, communityId) => { +const isBannedFromCommunity = async (user: UserDocument, communityId: string) => { try { if (!communityId) return false; const community = await Community.findOne({ _id: communityId }); if (!community) return false; - return community.banned_users.some(buser => buser.id == user._id); + return community.banned_users.toObject().some((buser: ICommunity) => buser.id == user._id); } catch (error) { logger.error(error); return false; diff --git a/db_connect.js b/db_connect.ts similarity index 81% rename from db_connect.js rename to db_connect.ts index e38fbd10..e93a8f7b 100644 --- a/db_connect.js +++ b/db_connect.ts @@ -1,5 +1,5 @@ -const mongoose = require('mongoose'); -const logger = require('./logger'); +import mongoose, { ConnectOptions } from "mongoose"; +import logger from "./logger"; // connect to database const credentials = process.env.DB_USER @@ -16,8 +16,8 @@ const connect = () => { mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, - }); + } as ConnectOptions); return mongoose; }; -module.exports = connect; +export default connect; diff --git a/jobs/calculate_community_earnings.js b/jobs/calculate_community_earnings.ts similarity index 78% rename from jobs/calculate_community_earnings.js rename to jobs/calculate_community_earnings.ts index 56151d48..54e59b23 100644 --- a/jobs/calculate_community_earnings.js +++ b/jobs/calculate_community_earnings.ts @@ -1,5 +1,5 @@ -const { Order, Community } = require('../models'); -const logger = require('../logger'); +import { Order, Community } from '../models'; +import logger from "../logger"; const calculateEarnings = async () => { try { @@ -12,9 +12,9 @@ const calculateEarnings = async () => { for (const order of orders) { const amount = order.amount; const fee = order.fee; - const botFee = order.bot_fee || parseFloat(process.env.MAX_FEE); + const botFee = order.bot_fee || Number(process.env.MAX_FEE); const communityFeePercent = - order.community_fee || parseFloat(process.env.FEE_PERCENT); + order.community_fee || Number(process.env.FEE_PERCENT); const maxFee = amount * botFee; const communityFee = fee - maxFee * communityFeePercent; const earnings = earningsMap.get(order.community_id) || [0, 0]; @@ -27,6 +27,7 @@ const calculateEarnings = async () => { } for (const [communityId, earnings] of earningsMap) { const community = await Community.findById(communityId); + if (community === null) throw Error("Community was not found in DB"); const amount = Math.round(earnings[0]); community.earnings = community.earnings + amount; community.orders_to_redeem = community.orders_to_redeem + earnings[1]; @@ -36,9 +37,9 @@ const calculateEarnings = async () => { ); } } catch (error) { - const message = error.toString(); + const message = String(error); logger.error(`calculateEarnings catch error: ${message}`); } }; -module.exports = calculateEarnings; +export default calculateEarnings; diff --git a/jobs/cancel_orders.js b/jobs/cancel_orders.ts similarity index 85% rename from jobs/cancel_orders.js rename to jobs/cancel_orders.ts index 00cef019..0879a056 100644 --- a/jobs/cancel_orders.js +++ b/jobs/cancel_orders.ts @@ -1,15 +1,17 @@ -const { User, Order } = require('../models'); +import { Telegraf } from "telegraf"; +import { MainContext } from "../bot/start"; +import { User, Order } from "../models"; const { cancelShowHoldInvoice, cancelAddInvoice } = require('../bot/commands'); -const messages = require('../bot/messages'); -const { getUserI18nContext, holdInvoiceExpirationInSecs } = require('../util'); -const logger = require('../logger'); +import * as messages from "../bot/messages"; +import { getUserI18nContext, holdInvoiceExpirationInSecs } from '../util'; +import logger from "../logger"; -const cancelOrders = async bot => { +const cancelOrders = async (bot: Telegraf) => { try { const holdInvoiceTime = new Date(); holdInvoiceTime.setSeconds( holdInvoiceTime.getSeconds() - - parseInt(process.env.HOLD_INVOICE_EXPIRATION_WINDOW) + Number(process.env.HOLD_INVOICE_EXPIRATION_WINDOW) ); // We get the orders where the seller didn't pay the hold invoice before expired // or where the buyer didn't add the invoice @@ -45,6 +47,7 @@ const cancelOrders = async bot => { for (const order of activeOrders) { const buyerUser = await User.findOne({ _id: order.buyer_id }); const sellerUser = await User.findOne({ _id: order.seller_id }); + if (buyerUser === null || sellerUser === null) return; const i18nCtxBuyer = await getUserI18nContext(buyerUser); const i18nCtxSeller = await getUserI18nContext(sellerUser); // Instead of cancel this order we should send this to the admins @@ -70,7 +73,7 @@ const cancelOrders = async bot => { // Now we cancel orders expired // ============================== orderTime = new Date(); - let orderExpirationTime = parseInt( + let orderExpirationTime = Number( process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW ); orderExpirationTime = orderExpirationTime + orderExpirationTime * 0.2; @@ -96,4 +99,4 @@ const cancelOrders = async bot => { } }; -module.exports = cancelOrders; +export default cancelOrders; diff --git a/jobs/communities.js b/jobs/communities.ts similarity index 70% rename from jobs/communities.js rename to jobs/communities.ts index e9ddb503..c57b5d49 100644 --- a/jobs/communities.js +++ b/jobs/communities.ts @@ -1,12 +1,15 @@ -const { Order, Community } = require('../models'); -const logger = require('../logger'); +import { Telegraf } from "telegraf"; +import { MainContext } from "../bot/start"; -const deleteCommunity = async bot => { +import { Order, Community } from '../models'; +import logger from "../logger"; + +const deleteCommunity = async (bot: Telegraf) => { try { const communities = await Community.find(); for (const community of communities) { // Delete communities with COMMUNITY_TTL days without a successful order - const days = 86400 * parseInt(process.env.COMMUNITY_TTL); + const days = 86400 * Number(process.env.COMMUNITY_TTL); const time = new Date(); time.setSeconds(time.getSeconds() - days); // If is a new community we don't do anything @@ -26,9 +29,9 @@ const deleteCommunity = async bot => { } } } catch (error) { - const message = error.toString(); + const message = String(error); logger.error(`deleteCommunity catch error: ${message}`); } }; -module.exports = deleteCommunity; +export default deleteCommunity; diff --git a/jobs/delete_published_orders.js b/jobs/delete_published_orders.ts similarity index 73% rename from jobs/delete_published_orders.js rename to jobs/delete_published_orders.ts index b4e284ae..18c2134a 100644 --- a/jobs/delete_published_orders.js +++ b/jobs/delete_published_orders.ts @@ -1,13 +1,16 @@ -const { Order } = require('../models'); +import { Telegraf } from "telegraf"; +import { MainContext } from "../bot/start"; + +import { Order } from '../models'; const { deleteOrderFromChannel } = require('../util'); -const logger = require('../logger'); +import logger from "../logger"; -const deleteOrders = async bot => { +const deleteOrders = async (bot: Telegraf) => { try { const windowTime = new Date(); windowTime.setSeconds( windowTime.getSeconds() - - parseInt(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW) + Number(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW) ); // We get the pending orders where time is expired const pendingOrders = await Order.find({ @@ -25,9 +28,9 @@ const deleteOrders = async bot => { await deleteOrderFromChannel(orderCloned, bot.telegram); } } catch (error) { - const message = error.toString(); + const message = String(error); logger.error(`deleteOrders catch error: ${message}`); } }; -module.exports = deleteOrders; +export default deleteOrders; diff --git a/jobs/index.js b/jobs/index.js deleted file mode 100644 index b784f178..00000000 --- a/jobs/index.js +++ /dev/null @@ -1,19 +0,0 @@ -const { - attemptPendingPayments, - attemptCommunitiesPendingPayments, -} = require('./pending_payments'); -const cancelOrders = require('./cancel_orders'); -const deleteOrders = require('./delete_published_orders'); -const calculateEarnings = require('./calculate_community_earnings'); -const deleteCommunity = require('./communities'); -const nodeInfo = require('./node_info'); - -module.exports = { - attemptPendingPayments, - cancelOrders, - deleteOrders, - calculateEarnings, - attemptCommunitiesPendingPayments, - deleteCommunity, - nodeInfo, -}; diff --git a/jobs/index.ts b/jobs/index.ts new file mode 100644 index 00000000..281f16f6 --- /dev/null +++ b/jobs/index.ts @@ -0,0 +1,19 @@ +import { + attemptPendingPayments, + attemptCommunitiesPendingPayments, +} from "./pending_payments"; +import cancelOrders from "./cancel_orders"; +import deleteOrders from "./delete_published_orders"; +import calculateEarnings from './calculate_community_earnings' +import deleteCommunity from './communities' +import nodeInfo from './node_info' + +export { + attemptPendingPayments, + cancelOrders, + deleteOrders, + calculateEarnings, + attemptCommunitiesPendingPayments, + deleteCommunity, + nodeInfo, +}; diff --git a/jobs/node_info.js b/jobs/node_info.ts similarity index 51% rename from jobs/node_info.js rename to jobs/node_info.ts index bad5d904..0caa7c5b 100644 --- a/jobs/node_info.js +++ b/jobs/node_info.ts @@ -1,10 +1,14 @@ -const { Config } = require('../models'); +import { Telegraf } from "telegraf"; +import { MainContext } from "../bot/start"; + +import { Config } from '../models'; const { getInfo } = require('../ln'); -const logger = require('../logger'); +import logger from "../logger"; -const info = async bot => { +const info = async (bot: Telegraf) => { try { const config = await Config.findOne({}); + if (config === null) throw Error("Config not found in DB"); const info = await getInfo(); if (info.is_synced_to_chain) { config.node_status = 'up'; @@ -12,9 +16,9 @@ const info = async bot => { config.node_uri = info.uris[0]; await config.save(); } catch (error) { - const message = error.toString(); + const message = String(error); logger.error(`node info catch error: ${message}`); } }; -module.exports = info; +export default info; diff --git a/jobs/pending_payments.ts b/jobs/pending_payments.ts index 80b79135..3cd8e295 100644 --- a/jobs/pending_payments.ts +++ b/jobs/pending_payments.ts @@ -1,13 +1,13 @@ -const { payRequest, isPendingPayment } = require('../ln'); -const { PendingPayment, Order, User, Community } = require('../models'); -const messages = require('../bot/messages'); -const { getUserI18nContext } = require('../util'); -const logger = require('../logger'); +import { PendingPayment, Order, User, Community } from '../models'; +import * as messages from '../bot/messages'; +import logger from "../logger"; import { Telegraf } from 'telegraf'; import { I18nContext } from '@grammyjs/i18n'; import { MainContext } from '../bot/start'; +const { payRequest, isPendingPayment } = require('../ln'); +const { getUserI18nContext } = require('../util'); -exports.attemptPendingPayments = async (bot: Telegraf): Promise => { +export const attemptPendingPayments = async (bot: Telegraf): Promise => { const pendingPayments = await PendingPayment.find({ paid: false, attempts: { $lt: process.env.PAYMENT_ATTEMPTS }, @@ -17,6 +17,7 @@ exports.attemptPendingPayments = async (bot: Telegraf): Promise): Promise): Promise): Promise): Promise => { +export const attemptCommunitiesPendingPayments = async (bot: Telegraf): Promise => { const pendingPayments = await PendingPayment.find({ paid: false, attempts: { $lt: process.env.PAYMENT_ATTEMPTS }, @@ -134,6 +139,7 @@ exports.attemptCommunitiesPendingPayments = async (bot: Telegraf): request: pending.payment_request, }); const user = await User.findById(pending.user_id); + if (user === null) throw Error("User was not found in DB"); const i18nCtx: I18nContext = await getUserI18nContext(user); // If the buyer's invoice is expired we let it know and don't try to pay again if (!!payment && payment.is_expired) { @@ -145,9 +151,10 @@ exports.attemptCommunitiesPendingPayments = async (bot: Telegraf): } const community = await Community.findById(pending.community_id); + if (community === null) throw Error("Community was not found in DB"); if (!!payment && !!payment.confirmed_at) { pending.paid = true; - pending.paid_at = new Date().toISOString(); + pending.paid_at = new Date(); // Reset the community's values community.earnings = 0; diff --git a/ln/connect.js b/ln/connect.ts similarity index 89% rename from ln/connect.js rename to ln/connect.ts index 167d5445..f82b5c04 100644 --- a/ln/connect.js +++ b/ln/connect.ts @@ -1,7 +1,7 @@ -const fs = require('fs'); -const path = require('path'); -const lightning = require('lightning'); -const logger = require('../logger'); +import * as fs from 'fs'; +import * as path from 'path'; +import * as lightning from "lightning"; +import logger from "../logger"; const { authenticatedLndGrpc } = lightning; @@ -47,4 +47,4 @@ const { lnd } = authenticatedLndGrpc({ socket, }); -module.exports = lnd; +export { lnd }; diff --git a/ln/hold_invoice.js b/ln/hold_invoice.ts similarity index 61% rename from ln/hold_invoice.js rename to ln/hold_invoice.ts index 1a36c39c..201d644c 100644 --- a/ln/hold_invoice.js +++ b/ln/hold_invoice.ts @@ -1,26 +1,26 @@ -const { createHash, randomBytes } = require('crypto'); -const lightning = require('lightning'); -const lnd = require('./connect'); -const logger = require('../logger'); +import { randomBytes, createHash } from 'crypto'; +import * as lightning from "lightning"; +import { lnd } from './connect' +import logger from "../logger"; -const createHoldInvoice = async ({ description, amount }) => { +const createHoldInvoice = async (description: string, amount: number ) => { try { const randomSecret = () => randomBytes(32); - const sha256 = buffer => createHash('sha256').update(buffer).digest('hex'); + const sha256 = (buffer: Buffer): string => createHash('sha256').update(buffer).digest('hex'); // We create a random secret const secret = randomSecret(); const expiresAt = new Date(); expiresAt.setSeconds(expiresAt.getSeconds() + 3600); const hash = sha256(secret); - const cltv_delta = parseInt(process.env.HOLD_INVOICE_CLTV_DELTA); + const cltv_delta = Number(process.env.HOLD_INVOICE_CLTV_DELTA); const { request, id } = await lightning.createHodlInvoice({ cltv_delta, lnd, description, id: hash, tokens: amount, - expires_at: expiresAt, + expires_at: expiresAt.toISOString(), }); // We sent back the response hash (id) to be used on testing @@ -30,7 +30,7 @@ const createHoldInvoice = async ({ description, amount }) => { } }; -const settleHoldInvoice = async ({ secret }) => { +const settleHoldInvoice = async ( { secret }: { secret: string } ) => { try { await lightning.settleHodlInvoice({ lnd, secret }); } catch (error) { @@ -38,7 +38,7 @@ const settleHoldInvoice = async ({ secret }) => { } }; -const cancelHoldInvoice = async ({ hash }) => { +const cancelHoldInvoice = async ( { hash }: { hash: string } ) => { try { await lightning.cancelHodlInvoice({ lnd, id: hash }); } catch (error) { @@ -46,7 +46,7 @@ const cancelHoldInvoice = async ({ hash }) => { } }; -const getInvoice = async ({ hash }) => { +const getInvoice = async ( { hash }: { hash: string } ) => { try { return await lightning.getInvoice({ lnd, id: hash }); } catch (error) { @@ -54,7 +54,7 @@ const getInvoice = async ({ hash }) => { } }; -module.exports = { +export { createHoldInvoice, settleHoldInvoice, cancelHoldInvoice, diff --git a/ln/index.js b/ln/index.ts similarity index 64% rename from ln/index.js rename to ln/index.ts index 109300f8..57372418 100644 --- a/ln/index.js +++ b/ln/index.ts @@ -1,16 +1,16 @@ -const { +import { createHoldInvoice, settleHoldInvoice, cancelHoldInvoice, getInvoice, -} = require('./hold_invoice'); -const subscribeInvoice = require('./subscribe_invoice'); +} from './hold_invoice'; +import subscribeInvoice from './subscribe_invoice'; const subscribeProbe = require('./subscribe_probe'); -const resubscribeInvoices = require('./resubscribe_invoices'); +import resubscribeInvoices from './resubscribe_invoices'; const { payRequest, payToBuyer, isPendingPayment } = require('./pay_request'); -const { getInfo } = require('./info'); +import { getInfo } from './info'; -module.exports = { +export { createHoldInvoice, subscribeInvoice, resubscribeInvoices, @@ -22,4 +22,4 @@ module.exports = { isPendingPayment, subscribeProbe, getInvoice, -}; +} diff --git a/ln/info.js b/ln/info.js deleted file mode 100644 index da731135..00000000 --- a/ln/info.js +++ /dev/null @@ -1,13 +0,0 @@ -const lightning = require('lightning'); -const lnd = require('./connect'); -const logger = require('../logger'); - -const getInfo = async () => { - try { - return await lightning.getWalletInfo({ lnd }); - } catch (error) { - logger.error(error); - } -}; - -module.exports = { getInfo }; diff --git a/ln/info.ts b/ln/info.ts new file mode 100644 index 00000000..179fb82e --- /dev/null +++ b/ln/info.ts @@ -0,0 +1,11 @@ +import * as lightning from "lightning"; +import { lnd } from './connect' +import logger from "../logger"; + +export const getInfo = async () => { + try { + return await lightning.getWalletInfo({ lnd }); + } catch (error) { + logger.error(error); + } +}; diff --git a/ln/resubscribe_invoices.js b/ln/resubscribe_invoices.ts similarity index 65% rename from ln/resubscribe_invoices.js rename to ln/resubscribe_invoices.ts index 644dbbba..33ae6e90 100644 --- a/ln/resubscribe_invoices.js +++ b/ln/resubscribe_invoices.ts @@ -1,13 +1,15 @@ -const { getInvoices } = require('lightning'); -const lnd = require('./connect'); +import { Telegraf } from 'telegraf'; +import { MainContext } from "../bot/start"; +import { getInvoices, GetInvoicesResult } from 'lightning'; +import { lnd } from './connect'; const subscribeInvoice = require('./subscribe_invoice'); -const { Order } = require('../models'); -const logger = require('../logger'); +import { Order } from '../models'; +import logger from "../logger"; -const resubscribeInvoices = async bot => { +const resubscribeInvoices = async (bot: Telegraf) => { try { let invoicesReSubscribed = 0; - const isHeld = invoice => !!invoice.is_held; + const isHeld = (invoice: any) => !!invoice.is_held; const unconfirmedInvoices = ( await getInvoices({ lnd, @@ -29,9 +31,9 @@ const resubscribeInvoices = async bot => { } logger.info(`Invoices resubscribed: ${invoicesReSubscribed}`); } catch (error) { - logger.error(`ResuscribeInvoice catch: ${error.toString()}`); + logger.error(`ResuscribeInvoice catch: ${String(error)}`); return false; } }; -module.exports = resubscribeInvoices; +export default resubscribeInvoices diff --git a/ln/subscribe_invoice.js b/ln/subscribe_invoice.ts similarity index 82% rename from ln/subscribe_invoice.js rename to ln/subscribe_invoice.ts index 2f96e36a..fe5a5142 100644 --- a/ln/subscribe_invoice.js +++ b/ln/subscribe_invoice.ts @@ -1,23 +1,27 @@ -const { subscribeToInvoice } = require('lightning'); -const { Order, User } = require('../models'); +import { Telegraf } from "telegraf"; +import { MainContext } from "../bot/start"; +import {subscribeToInvoice} from 'lightning' +import { Order, User } from '../models'; const { payToBuyer } = require('./pay_request'); -const lnd = require('./connect'); -const messages = require('../bot/messages'); +import { lnd } from "./connect"; +import * as messages from '../bot/messages'; const ordersActions = require('../bot/ordersActions'); const { getUserI18nContext, getEmojiRate, decimalRound } = require('../util'); -const logger = require('../logger'); +import logger from "../logger"; -const subscribeInvoice = async (bot, id, resub) => { +const subscribeInvoice = async (bot: Telegraf, id: string, resub: boolean) => { try { const sub = subscribeToInvoice({ id, lnd }); sub.on('invoice_updated', async invoice => { if (invoice.is_held && !resub) { const order = await Order.findOne({ hash: invoice.id }); + if (order === null) throw Error("Order was not found in DB"); logger.info( `Order ${order._id} Invoice with hash: ${id} is being held!` ); const buyerUser = await User.findOne({ _id: order.buyer_id }); const sellerUser = await User.findOne({ _id: order.seller_id }); + if (buyerUser === null || sellerUser === null) throw Error("buyer or seller was not found in DB"); order.status = 'ACTIVE'; // This is the i18n context we need to pass to the message const i18nCtxBuyer = await getUserI18nContext(buyerUser); @@ -47,11 +51,12 @@ const subscribeInvoice = async (bot, id, resub) => { rate ); } - order.invoice_held_at = Date.now(); + order.invoice_held_at = new Date(); order.save(); } if (invoice.is_confirmed) { const order = await Order.findOne({ hash: id }); + if (order === null) throw Error("Order was not found in DB"); logger.info( `Order ${order._id} - Invoice with hash: ${id} was settled!` ); @@ -59,6 +64,7 @@ const subscribeInvoice = async (bot, id, resub) => { await order.save(); const buyerUser = await User.findOne({ _id: order.buyer_id }); const sellerUser = await User.findOne({ _id: order.seller_id }); + if (buyerUser === null || sellerUser === null) throw Error("buyer and/or seller was not found in DB"); // We need two i18n contexts to send messages to each user const i18nCtxBuyer = await getUserI18nContext(buyerUser); const i18nCtxSeller = await getUserI18nContext(sellerUser); @@ -121,4 +127,4 @@ const subscribeInvoice = async (bot, id, resub) => { } }; -module.exports = subscribeInvoice; +export default subscribeInvoice; diff --git a/lnurl/lnurl-pay.js b/lnurl/lnurl-pay.ts similarity index 77% rename from lnurl/lnurl-pay.js rename to lnurl/lnurl-pay.ts index 45235898..4ebc2e99 100644 --- a/lnurl/lnurl-pay.js +++ b/lnurl/lnurl-pay.ts @@ -1,11 +1,11 @@ -const axios = require('axios').default; -const logger = require('../logger'); +import axios from 'axios'; +import logger from "../logger"; // { // pr: String, // bech32-serialized lightning invoice // routes: [], // an empty array // } -const resolvLightningAddress = async (address, amountMsat) => { +const resolvLightningAddress = async (address: string, amountMsat: number) => { const [user, domain] = address.split('@'); const lnAddressQuery = `https://${domain}/.well-known/lnurlp/${user}`; @@ -17,7 +17,7 @@ const resolvLightningAddress = async (address, amountMsat) => { } if ( - (lnAddressRes.minSendable > amountMsat) | + (lnAddressRes.minSendable > amountMsat) || (lnAddressRes.maxSendable < amountMsat) ) { logger.info('lnAddress invalid amount'); @@ -31,7 +31,7 @@ const resolvLightningAddress = async (address, amountMsat) => { return res; }; -const existLightningAddress = async address => { +const existLightningAddress = async (address: string) => { const [user, domain] = address.split('@'); const lnAddressQuery = `https://${domain}/.well-known/lnurlp/${user}`; @@ -49,7 +49,4 @@ const existLightningAddress = async address => { } }; -module.exports = { - resolvLightningAddress, - existLightningAddress, -}; +export { resolvLightningAddress, existLightningAddress } diff --git a/logger.js b/logger.ts similarity index 82% rename from logger.js rename to logger.ts index ada7ed8e..d5fe6e2a 100644 --- a/logger.js +++ b/logger.ts @@ -1,4 +1,4 @@ -const winston = require('winston'); +import * as winston from 'winston'; const level = process.env.LOG_LEVEL || 'notice'; @@ -9,9 +9,8 @@ const logger = winston.createLogger({ }), winston.format.colorize(), winston.format.printf(info => { - return `[${info.timestamp}] ${info.level}: ${info.message} ${ - info.stack ? info.stack : '' - }`; + return `[${info.timestamp}] ${info.level}: ${info.message} ${info.stack ? info.stack : '' + }`; }) ), levels: winston.config.syslog.levels, @@ -24,4 +23,5 @@ const logger = winston.createLogger({ exitOnError: false, }); -module.exports = logger; + +export default logger; diff --git a/models/community.ts b/models/community.ts index 7321d9c7..09e34908 100644 --- a/models/community.ts +++ b/models/community.ts @@ -84,4 +84,4 @@ const CommunitySchema = new Schema({ }); -module.exports = mongoose.model('Community', CommunitySchema); +export default mongoose.model('Community', CommunitySchema); diff --git a/models/config.ts b/models/config.ts index f109d639..43dafece 100644 --- a/models/config.ts +++ b/models/config.ts @@ -13,5 +13,4 @@ const configSchema = new Schema({ node_uri: { type: String }, }); - -module.exports = mongoose.model('Config', configSchema); +export default mongoose.model('Config', configSchema); diff --git a/models/dispute.ts b/models/dispute.ts index 381a17e2..68f751c4 100644 --- a/models/dispute.ts +++ b/models/dispute.ts @@ -31,4 +31,4 @@ const DisputeSchema = new Schema({ created_at: { type: Date, default: Date.now }, }); -module.exports = mongoose.model('Dispute', DisputeSchema); +export default mongoose.model('Dispute', DisputeSchema); diff --git a/models/index.js b/models/index.js deleted file mode 100644 index 23dbfa94..00000000 --- a/models/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const User = require('./user'); -const Order = require('./order'); -const PendingPayment = require('./pending_payment'); -const Community = require('./community'); -const Dispute = require('./dispute'); -const Config = require('./config'); - -module.exports = { - User, - Order, - PendingPayment, - Community, - Dispute, - Config, -}; diff --git a/models/index.ts b/models/index.ts new file mode 100644 index 00000000..6fd610a7 --- /dev/null +++ b/models/index.ts @@ -0,0 +1,15 @@ +import User from './user' +import Order from './order' +import PendingPayment from './pending_payment' +import Community from './community' +import Dispute from './dispute' +import Config from './config' + +export { + User, + Order, + PendingPayment, + Community, + Dispute, + Config, +}; diff --git a/models/order.ts b/models/order.ts index b1bbf66b..1a2f0411 100644 --- a/models/order.ts +++ b/models/order.ts @@ -123,4 +123,4 @@ const orderSchema = new Schema({ is_public: { type: Boolean, default: true }, }); -module.exports = mongoose.model('Order', orderSchema); +export default mongoose.model('Order', orderSchema); diff --git a/models/pending_payment.ts b/models/pending_payment.ts index f2a81f3b..f324815b 100644 --- a/models/pending_payment.ts +++ b/models/pending_payment.ts @@ -40,4 +40,4 @@ const PendingPaymentSchema = new Schema({ }); -module.exports = mongoose.model('PendingPayment', PendingPaymentSchema); +export default mongoose.model('PendingPayment', PendingPaymentSchema); diff --git a/models/user.ts b/models/user.ts index 1bc7f227..adc8f375 100644 --- a/models/user.ts +++ b/models/user.ts @@ -52,4 +52,4 @@ const UserSchema = new Schema({ default_community_id: { type: String }, }); -module.exports = mongoose.model('User', UserSchema); +export default mongoose.model('User', UserSchema); diff --git a/package-lock.json b/package-lock.json index c7e08854..1f512338 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "lnp2pbot", - "version": "0.8.5", + "version": "0.9.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "lnp2pbot", - "version": "0.8.5", + "version": "0.9.2", "license": "MIT", "dependencies": { "@grammyjs/i18n": "^0.5.1", @@ -27,6 +27,8 @@ }, "devDependencies": { "@types/node": "^20.5.0", + "@types/node-schedule": "^2.1.0", + "@types/qrcode": "^1.5.2", "chai": "^4.3.4", "chokidar": "^3.5.3", "eslint": "^8.15.0", @@ -1640,6 +1642,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==" }, + "node_modules/@types/node-schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.0.tgz", + "integrity": "sha512-NiTwl8YN3v/1YCKrDFSmCTkVxFDylueEqsOFdgF+vPsm+AlyJKGAo5yzX1FiOxPsZiN6/r8gJitYx2EaSuBmmg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qrcode": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.2.tgz", + "integrity": "sha512-W4KDz75m7rJjFbyCctzCtRzZUj+PrUHV+YjqDp50sSRezTbrtEAIq2iTzC6lISARl3qw+8IlcCyljdcVJE0Wug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -8462,6 +8482,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==" }, + "@types/node-schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.0.tgz", + "integrity": "sha512-NiTwl8YN3v/1YCKrDFSmCTkVxFDylueEqsOFdgF+vPsm+AlyJKGAo5yzX1FiOxPsZiN6/r8gJitYx2EaSuBmmg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/qrcode": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.2.tgz", + "integrity": "sha512-W4KDz75m7rJjFbyCctzCtRzZUj+PrUHV+YjqDp50sSRezTbrtEAIq2iTzC6lISARl3qw+8IlcCyljdcVJE0Wug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", diff --git a/package.json b/package.json index d4e5f29b..428ee893 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,8 @@ ], "devDependencies": { "@types/node": "^20.5.0", + "@types/qrcode": "^1.5.2", + "@types/node-schedule": "^2.1.0", "chai": "^4.3.4", "chokidar": "^3.5.3", "eslint": "^8.15.0", diff --git a/tests/bot_test.js b/tests/bot_test.js index df4ceca5..0feb9570 100644 --- a/tests/bot_test.js +++ b/tests/bot_test.js @@ -10,7 +10,7 @@ const ordersActions = require('../bot/ordersActions'); const testUser = require('./user'); const testOrder = require('./order'); const { getCurrenciesWithPrice } = require('../util'); -const mongoConnect = require('../db_connect'); +const mongoConnect = require('../db_connect').default; mongoConnect(); diff --git a/tsconfig.json b/tsconfig.json index 8039f57e..7b8d0663 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,8 @@ { "compilerOptions": { "strict": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "downlevelIteration": true } } diff --git a/util/fiatModel.ts b/util/fiatModel.ts index a722adc0..cc8d22e8 100644 --- a/util/fiatModel.ts +++ b/util/fiatModel.ts @@ -10,3 +10,7 @@ export interface IFiat { price?: boolean; locale?: string; } + +export interface IFiatCurrencies { + [key: string]: IFiat; +} diff --git a/util/index.js b/util/index.ts similarity index 73% rename from util/index.js rename to util/index.ts index 8cb13f63..a9165729 100644 --- a/util/index.js +++ b/util/index.ts @@ -1,18 +1,28 @@ -const axios = require('axios'); +import { I18nContext } from "@grammyjs/i18n"; +import { ICommunity, IOrderChannel } from "../models/community"; +import { IOrder } from "../models/order"; +import { UserDocument } from "../models/user"; +import { IFiatCurrencies, IFiat } from "./fiatModel"; +import { ILanguage, ILanguages } from "./languagesModel"; +import { Telegram } from "telegraf/typings/core/types/typegram"; +import axios from "axios"; +import fiatJson from './fiat.json'; +import languagesJson from './languages.json'; +import { Order, Community } from "../models"; +import logger from "../logger"; const { I18n } = require('@grammyjs/i18n'); -const currencies = require('./fiat.json'); -const languages = require('./languages.json'); -const { Order, Community } = require('../models'); -const logger = require('../logger'); + +const languages: ILanguages = languagesJson; +const currencies: IFiatCurrencies = fiatJson; // ISO 4217, all ISO currency codes are 3 letters but users can trade shitcoins -const isIso4217 = code => { +const isIso4217 = (code: string): boolean => { if (code.length < 3 || code.length > 5) { return false; } const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split(''); - code = code.toLowerCase().split(''); - return code.every(letter => { + code = code.toLowerCase() + return code.split('').every(letter => { if (alphabet.indexOf(letter) == -1) { return false; } @@ -20,15 +30,15 @@ const isIso4217 = code => { }); }; -const getCurrency = code => { - if (!isIso4217(code)) return false; +const getCurrency = (code: string): (IFiat | null) => { + if (!isIso4217(code)) return null; const currency = currencies[code]; - if (!currency) return false; + if (!currency) return null; return currency; }; -const plural = n => { +const plural = (n: number): string => { if (n === 1) { return ''; } @@ -37,7 +47,7 @@ const plural = n => { // This function formats a number to locale strings. // If Iso code or locale code doesn´t exist, the function will return a number without format. -const numberFormat = (code, number) => { +const numberFormat = (code: string, number: number) => { if (!isIso4217(code)) return false; if (!currencies[code]) return number; @@ -53,7 +63,7 @@ const numberFormat = (code, number) => { // This function checks if the current buyer and seller were doing circular operations // In order to increase their trades_completed and volume_traded. // If we found those trades in the last 24 hours we decrease both variables to both users -const handleReputationItems = async (buyer, seller, amount) => { +const handleReputationItems = async (buyer: UserDocument, seller: UserDocument, amount: number) => { try { const yesterday = new Date(Date.now() - 86400000).toISOString(); const orders = await Order.find({ @@ -64,7 +74,7 @@ const handleReputationItems = async (buyer, seller, amount) => { }); if (orders.length > 0) { let totalAmount = 0; - orders.forEach(order => { + orders.forEach((order: IOrder) => { totalAmount += order.amount; }); const lastAmount = orders[orders.length - 1].amount; @@ -118,9 +128,10 @@ const handleReputationItems = async (buyer, seller, amount) => { } }; -const getBtcFiatPrice = async (fiatCode, fiatAmount) => { +const getBtcFiatPrice = async (fiatCode: string, fiatAmount: number) => { try { const currency = getCurrency(fiatCode); + if (currency === null) throw Error("Currency not found"); if (!currency.price) return; // Before hit the endpoint we make sure the code have only 3 chars const code = currency.code.substring(0, 3); @@ -130,13 +141,13 @@ const getBtcFiatPrice = async (fiatCode, fiatAmount) => { } const sats = (fiatAmount / response.data.btc) * 100000000; - return parseInt(sats); + return Number(sats); } catch (error) { logger.error(error); } }; -const getBtcExchangePrice = (fiatAmount, satsAmount) => { +const getBtcExchangePrice = (fiatAmount: number, satsAmount: number) => { try { const satsPerBtc = 1e8; const feeRate = (satsPerBtc * fiatAmount) / satsAmount; @@ -147,8 +158,8 @@ const getBtcExchangePrice = (fiatAmount, satsAmount) => { } }; -const objectToArray = object => { - const array = []; +const objectToArray = (object: any): any[] => { + const array: any[] = []; for (const i in object) array.push(object[i]); @@ -162,7 +173,7 @@ const getCurrenciesWithPrice = () => { return withPrice; }; -const getEmojiRate = rate => { +const getEmojiRate = (rate: number): string => { const star = '⭐'; const roundedRate = Math.round(rate); const output = []; @@ -173,7 +184,7 @@ const getEmojiRate = rate => { // Round number to exp decimal digits // Source: https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Math/round#redondeo_decimal -const decimalRound = (value, exp) => { +const decimalRound = (value: number, exp: number): number => { if (typeof exp === 'undefined' || +exp === 0) { return Math.round(value); } @@ -184,27 +195,29 @@ const decimalRound = (value, exp) => { return NaN; } // Shift - value = value.toString().split('e'); - value = Math.round(+(value[0] + 'e' + (value[1] ? +value[1] - exp : -exp))); + let valueArr = value.toString().split('e'); + value = Math.round(+(valueArr[0] + 'e' + (valueArr[1] ? +valueArr[1] - exp : -exp))); // Shift back - value = value.toString().split('e'); - return +(value[0] + 'e' + (value[1] ? +value[1] + exp : exp)); + valueArr = value.toString().split('e'); + return +(valueArr[0] + 'e' + (valueArr[1] ? +valueArr[1] + exp : exp)); }; -const extractId = text => { +const extractId = (text: string): (string | null) => { const matches = text.match(/:([a-f0-9]{24}):$/); - - return matches[1]; + if (matches !== null){ + return matches?.[1]; + } + return null; }; // Clean strings that are going to be rendered with markdown -const sanitizeMD = text => { +const sanitizeMD = (text: any) => { if (!text) return ''; - return text.toString().replace(/(?=[|<>(){}[\]\-_!#.`=+])/g, '\\'); + return String(text).replace(/(?=[|<>(){}[\]\-_!#.`=+])/g, '\\'); }; -const secondsToTime = secs => { +const secondsToTime = (secs: number) => { const hours = Math.floor(secs / (60 * 60)); const divisor = secs % (60 * 60); @@ -216,9 +229,9 @@ const secondsToTime = secs => { }; }; -const isGroupAdmin = async (groupId, user, telegram) => { +const isGroupAdmin = async (groupId: string, user: UserDocument, telegram: Telegram) => { try { - const member = await telegram.getChatMember(groupId, user.tg_id); + const member = await telegram.getChatMember({chat_id: groupId, user_id: Number(user.tg_id)}); if ( member && (member.status === 'creator' || member.status === 'administrator') @@ -242,12 +255,12 @@ const isGroupAdmin = async (groupId, user, telegram) => { logger.error(error); return { success: false, - message: error.toString(), + message: String(error), }; } }; -const deleteOrderFromChannel = async (order, telegram) => { +const deleteOrderFromChannel = async (order: IOrder, telegram: Telegram) => { try { let channel = process.env.CHANNEL; if (order.community_id) { @@ -265,13 +278,13 @@ const deleteOrderFromChannel = async (order, telegram) => { } } } - await telegram.deleteMessage(channel, order.tg_channel_message1); + await telegram.deleteMessage({chat_id: channel!, message_id: Number(order.tg_channel_message1!)}); } catch (error) { logger.error(error); } }; -const getOrderChannel = async order => { +const getOrderChannel = async (order: IOrder) => { let channel = process.env.CHANNEL; if (order.community_id) { const community = await Community.findOne({ _id: order.community_id }); @@ -281,7 +294,7 @@ const getOrderChannel = async order => { if (community.order_channels.length === 1) { channel = community.order_channels[0].name; } else { - community.order_channels.forEach(async c => { + community.order_channels.forEach(async (c: IOrderChannel) => { if (c.type === order.type) { channel = c.name; } @@ -292,10 +305,11 @@ const getOrderChannel = async order => { return channel; }; -const getDisputeChannel = async order => { +const getDisputeChannel = async (order: IOrder) => { let channel = process.env.DISPUTE_CHANNEL; if (order.community_id) { const community = await Community.findOne({ _id: order.community_id }); + if (community === null) throw Error("Community was not found in DB"); channel = community.dispute_channel; } @@ -307,8 +321,13 @@ const getDisputeChannel = async order => { * @param {*} user * @returns i18n context */ -const getUserI18nContext = async user => { - const language = user.language || 'en'; +const getUserI18nContext = async (user: UserDocument) => { + let language = null; + if (!('language' in user)) { + language = 'en'; + } else { + language = user.language; + } const i18n = new I18n({ locale: language, defaultLanguageOnMissing: true, @@ -318,7 +337,7 @@ const getUserI18nContext = async user => { return i18n.createContext(user.lang); }; -const getDetailedOrder = (i18n, order, buyer, seller) => { +const getDetailedOrder = (i18n: I18nContext, order: IOrder, buyer: UserDocument, seller: UserDocument) => { try { const buyerUsername = buyer ? sanitizeMD(buyer.username) : ''; const buyerReputation = buyer @@ -336,7 +355,7 @@ const getDetailedOrder = (i18n, order, buyer, seller) => { createdAt = sanitizeMD(createdAt); takenAt = sanitizeMD(takenAt); const status = sanitizeMD(order.status); - const fee = order.fee ? parseInt(order.fee) : ''; + const fee = order.fee ? Number(order.fee) : ''; const creator = order.creator_id === buyerId ? buyerUsername : sellerUsername; const message = i18n.t('order_detail', { @@ -361,7 +380,7 @@ const getDetailedOrder = (i18n, order, buyer, seller) => { }; // We need to know if this user is a dispute solver for this community -const isDisputeSolver = (community, user) => { +const isDisputeSolver = (community: ICommunity, user: UserDocument) => { if (!community || !user) { return false; } @@ -371,37 +390,35 @@ const isDisputeSolver = (community, user) => { // Return the fee the bot will charge to the seller // this fee is a combination from the global bot fee and the community fee -const getFee = async (amount, communityId) => { - const maxFee = Math.round(amount * parseFloat(process.env.MAX_FEE)); +const getFee = async (amount: number, communityId: string) => { + const maxFee = Math.round(amount * Number(process.env.MAX_FEE)); if (!communityId) return maxFee; - const botFee = maxFee * parseFloat(process.env.FEE_PERCENT); + const botFee = maxFee * Number(process.env.FEE_PERCENT); let communityFee = Math.round(maxFee - botFee); const community = await Community.findOne({ _id: communityId }); + if (community === null) throw Error("Community was not found in DB"); communityFee = communityFee * (community.fee / 100); return botFee + communityFee; }; -const itemsFromMessage = str => { +const itemsFromMessage = (str: string) => { return str .split(' ') .map(e => e.trim()) .filter(e => !!e); }; -// Check if a number is int -const isInt = n => parseInt(n) === n; - // Check if a number is float -const isFloat = n => typeof n === 'number' && !isInt(n); +const isFloat = (n: number) => typeof n === 'number' && !Number.isInteger(n); // Returns an emoji flag for a language -const getLanguageFlag = code => { +const getLanguageFlag = (code: string): ILanguage => { return languages[code]; }; -const delay = time => { +const delay = (time: number) => { return new Promise(resolve => setTimeout(resolve, time)); }; @@ -409,9 +426,9 @@ const delay = time => { // and the hold invoice safety window in seconds const holdInvoiceExpirationInSecs = () => { const expirationTimeInSecs = - parseInt(process.env.HOLD_INVOICE_CLTV_DELTA) * 10 * 60; + Number(process.env.HOLD_INVOICE_CLTV_DELTA) * 10 * 60; const safetyWindowInSecs = - parseInt(process.env.HOLD_INVOICE_CLTV_DELTA_SAFETY_WINDOW) * 10 * 60; + Number(process.env.HOLD_INVOICE_CLTV_DELTA_SAFETY_WINDOW) * 10 * 60; return { expirationTimeInSecs, safetyWindowInSecs, @@ -419,7 +436,7 @@ const holdInvoiceExpirationInSecs = () => { }; // Returns the user age in days -const getUserAge = user => { +const getUserAge = (user: UserDocument) => { const userCreationDate = new Date(user.created_at); const today = new Date(); const ageInDays = Math.floor( @@ -434,13 +451,13 @@ const getUserAge = user => { * @param {*} i18n context * @returns String with the remaining time to expiration in format '1 hours 30 minutes' */ -const getTimeToExpirationOrder = (order, i18n) => { +const getTimeToExpirationOrder = (order: IOrder, i18n: I18nContext) => { const initialDateObj = new Date(order.created_at); - const timeToExpire = parseInt(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW); + const timeToExpire = Number(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW); initialDateObj.setSeconds(initialDateObj.getSeconds() + timeToExpire); const currentDateObj = new Date(); - const timeDifferenceMs = initialDateObj - currentDateObj; + const timeDifferenceMs = initialDateObj.valueOf() - currentDateObj.valueOf(); const totalSecondsRemaining = Math.floor(timeDifferenceMs / 1000); const textHour = i18n.t('hours'); const textMin = i18n.t('minutes'); @@ -454,7 +471,7 @@ const getTimeToExpirationOrder = (order, i18n) => { return `${hours} ${textHour} ${minutes} ${textMin}`; }; -module.exports = { +export { isIso4217, plural, getCurrency, @@ -477,7 +494,6 @@ module.exports = { isDisputeSolver, getFee, itemsFromMessage, - isInt, isFloat, getLanguageFlag, delay, diff --git a/util/languagesModel.ts b/util/languagesModel.ts new file mode 100644 index 00000000..fa159815 --- /dev/null +++ b/util/languagesModel.ts @@ -0,0 +1,9 @@ +export interface ILanguage { + name: string; + emoji: string; + code: string; +} + +export interface ILanguages { + [key: string]: ILanguage; +} From 44d23985613f070feec37ec655523cfdbeb37513 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 25 Oct 2023 13:50:02 +0330 Subject: [PATCH 2/6] fix: remove all of the export default Since we also have JS files in our project, if we want to use export defaults we have to use default property: ``` var bar = require('./input').default; ``` I preferred named export over export default since it required a lot of changes to the JS files. --- app.ts | 4 ++-- bot/messages.ts | 2 +- db_connect.ts | 4 ++-- jobs/calculate_community_earnings.ts | 4 ++-- jobs/cancel_orders.ts | 4 ++-- jobs/communities.ts | 4 ++-- jobs/delete_published_orders.ts | 4 ++-- jobs/index.ts | 10 +++++----- jobs/node_info.ts | 4 ++-- jobs/pending_payments.ts | 2 +- ln/index.ts | 4 ++-- ln/resubscribe_invoices.ts | 4 ++-- ln/subscribe_invoice.ts | 2 +- lnurl/lnurl-pay.ts | 2 +- logger.ts | 2 +- tests/bot_test.js | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app.ts b/app.ts index 1809beec..498240f3 100644 --- a/app.ts +++ b/app.ts @@ -2,9 +2,9 @@ import * as dotenv from "dotenv"; dotenv.config() import { SocksProxyAgent } from "socks-proxy-agent"; import { MainContext, start } from "./bot/start"; -import mongoConnect from './db_connect' +import { connect as mongoConnect } from './db_connect' const { resubscribeInvoices } = require('./ln'); -import logger from "./logger"; +import { logger } from "./logger"; import { Telegraf } from "telegraf"; const { delay } = require('./util'); diff --git a/bot/messages.ts b/bot/messages.ts index a49ccac7..35aad6f5 100644 --- a/bot/messages.ts +++ b/bot/messages.ts @@ -12,7 +12,7 @@ const { decimalRound, getUserAge, } = require('../util'); -import logger from "../logger"; +import { logger } from "../logger"; import { MainContext } from './start'; import { UserDocument } from '../models/user' import { IOrder } from '../models/order' diff --git a/db_connect.ts b/db_connect.ts index e93a8f7b..c3ecb9b4 100644 --- a/db_connect.ts +++ b/db_connect.ts @@ -1,5 +1,5 @@ import mongoose, { ConnectOptions } from "mongoose"; -import logger from "./logger"; +import { logger } from "./logger"; // connect to database const credentials = process.env.DB_USER @@ -20,4 +20,4 @@ const connect = () => { return mongoose; }; -export default connect; +export { connect }; diff --git a/jobs/calculate_community_earnings.ts b/jobs/calculate_community_earnings.ts index 54e59b23..6d12fc92 100644 --- a/jobs/calculate_community_earnings.ts +++ b/jobs/calculate_community_earnings.ts @@ -1,5 +1,5 @@ import { Order, Community } from '../models'; -import logger from "../logger"; +import { logger } from "../logger"; const calculateEarnings = async () => { try { @@ -42,4 +42,4 @@ const calculateEarnings = async () => { } }; -export default calculateEarnings; +export { calculateEarnings }; diff --git a/jobs/cancel_orders.ts b/jobs/cancel_orders.ts index 0879a056..b574f4f4 100644 --- a/jobs/cancel_orders.ts +++ b/jobs/cancel_orders.ts @@ -4,7 +4,7 @@ import { User, Order } from "../models"; const { cancelShowHoldInvoice, cancelAddInvoice } = require('../bot/commands'); import * as messages from "../bot/messages"; import { getUserI18nContext, holdInvoiceExpirationInSecs } from '../util'; -import logger from "../logger"; +import { logger } from "../logger"; const cancelOrders = async (bot: Telegraf) => { try { @@ -99,4 +99,4 @@ const cancelOrders = async (bot: Telegraf) => { } }; -export default cancelOrders; +export { cancelOrders }; diff --git a/jobs/communities.ts b/jobs/communities.ts index c57b5d49..a18023f8 100644 --- a/jobs/communities.ts +++ b/jobs/communities.ts @@ -2,7 +2,7 @@ import { Telegraf } from "telegraf"; import { MainContext } from "../bot/start"; import { Order, Community } from '../models'; -import logger from "../logger"; +import { logger } from "../logger"; const deleteCommunity = async (bot: Telegraf) => { try { @@ -34,4 +34,4 @@ const deleteCommunity = async (bot: Telegraf) => { } }; -export default deleteCommunity; +export { deleteCommunity }; diff --git a/jobs/delete_published_orders.ts b/jobs/delete_published_orders.ts index 18c2134a..517d9d8b 100644 --- a/jobs/delete_published_orders.ts +++ b/jobs/delete_published_orders.ts @@ -3,7 +3,7 @@ import { MainContext } from "../bot/start"; import { Order } from '../models'; const { deleteOrderFromChannel } = require('../util'); -import logger from "../logger"; +import { logger } from "../logger"; const deleteOrders = async (bot: Telegraf) => { try { @@ -33,4 +33,4 @@ const deleteOrders = async (bot: Telegraf) => { } }; -export default deleteOrders; +export { deleteOrders }; diff --git a/jobs/index.ts b/jobs/index.ts index 281f16f6..f0279233 100644 --- a/jobs/index.ts +++ b/jobs/index.ts @@ -2,11 +2,11 @@ import { attemptPendingPayments, attemptCommunitiesPendingPayments, } from "./pending_payments"; -import cancelOrders from "./cancel_orders"; -import deleteOrders from "./delete_published_orders"; -import calculateEarnings from './calculate_community_earnings' -import deleteCommunity from './communities' -import nodeInfo from './node_info' +import { cancelOrders } from "./cancel_orders"; +import { deleteOrders } from "./delete_published_orders"; +import { calculateEarnings } from './calculate_community_earnings'; +import { deleteCommunity } from './communities'; +import { info as nodeInfo } from './node_info'; export { attemptPendingPayments, diff --git a/jobs/node_info.ts b/jobs/node_info.ts index 0caa7c5b..ccb16fe4 100644 --- a/jobs/node_info.ts +++ b/jobs/node_info.ts @@ -3,7 +3,7 @@ import { MainContext } from "../bot/start"; import { Config } from '../models'; const { getInfo } = require('../ln'); -import logger from "../logger"; +import { logger } from "../logger"; const info = async (bot: Telegraf) => { try { @@ -21,4 +21,4 @@ const info = async (bot: Telegraf) => { } }; -export default info; +export { info }; diff --git a/jobs/pending_payments.ts b/jobs/pending_payments.ts index 3cd8e295..aaa750be 100644 --- a/jobs/pending_payments.ts +++ b/jobs/pending_payments.ts @@ -1,6 +1,6 @@ import { PendingPayment, Order, User, Community } from '../models'; import * as messages from '../bot/messages'; -import logger from "../logger"; +import { logger } from "../logger"; import { Telegraf } from 'telegraf'; import { I18nContext } from '@grammyjs/i18n'; import { MainContext } from '../bot/start'; diff --git a/ln/index.ts b/ln/index.ts index 57372418..fc1c5f11 100644 --- a/ln/index.ts +++ b/ln/index.ts @@ -4,9 +4,9 @@ import { cancelHoldInvoice, getInvoice, } from './hold_invoice'; -import subscribeInvoice from './subscribe_invoice'; +import { subscribeInvoice } from './subscribe_invoice'; const subscribeProbe = require('./subscribe_probe'); -import resubscribeInvoices from './resubscribe_invoices'; +import { resubscribeInvoices } from './resubscribe_invoices'; const { payRequest, payToBuyer, isPendingPayment } = require('./pay_request'); import { getInfo } from './info'; diff --git a/ln/resubscribe_invoices.ts b/ln/resubscribe_invoices.ts index 33ae6e90..89d35485 100644 --- a/ln/resubscribe_invoices.ts +++ b/ln/resubscribe_invoices.ts @@ -4,7 +4,7 @@ import { getInvoices, GetInvoicesResult } from 'lightning'; import { lnd } from './connect'; const subscribeInvoice = require('./subscribe_invoice'); import { Order } from '../models'; -import logger from "../logger"; +import { logger } from "../logger"; const resubscribeInvoices = async (bot: Telegraf) => { try { @@ -36,4 +36,4 @@ const resubscribeInvoices = async (bot: Telegraf) => { } }; -export default resubscribeInvoices +export { resubscribeInvoices }; diff --git a/ln/subscribe_invoice.ts b/ln/subscribe_invoice.ts index fe5a5142..7700a479 100644 --- a/ln/subscribe_invoice.ts +++ b/ln/subscribe_invoice.ts @@ -127,4 +127,4 @@ const subscribeInvoice = async (bot: Telegraf, id: string, resub: b } }; -export default subscribeInvoice; +export { subscribeInvoice }; diff --git a/lnurl/lnurl-pay.ts b/lnurl/lnurl-pay.ts index 4ebc2e99..16ecf97d 100644 --- a/lnurl/lnurl-pay.ts +++ b/lnurl/lnurl-pay.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import logger from "../logger"; +import { logger } from "../logger"; // { // pr: String, // bech32-serialized lightning invoice diff --git a/logger.ts b/logger.ts index d5fe6e2a..df2e6d26 100644 --- a/logger.ts +++ b/logger.ts @@ -24,4 +24,4 @@ const logger = winston.createLogger({ }); -export default logger; +export { logger }; diff --git a/tests/bot_test.js b/tests/bot_test.js index 0feb9570..5a13934e 100644 --- a/tests/bot_test.js +++ b/tests/bot_test.js @@ -10,7 +10,7 @@ const ordersActions = require('../bot/ordersActions'); const testUser = require('./user'); const testOrder = require('./order'); const { getCurrenciesWithPrice } = require('../util'); -const mongoConnect = require('../db_connect').default; +const { connect: mongoConnect } = require('../db_connect'); mongoConnect(); From c411bfe96d62cca99a4f159c2e226348fa651c5d Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Mon, 23 Oct 2023 17:09:07 +0330 Subject: [PATCH 3/6] fix: logger.ts imports After porting logger.js to typescript, the logger type became a "named export", this changes the syntax for importing it. Additionally, there are a few mistakes in imports that we weren't noticed of. --- bot/commands.js | 2 +- bot/modules/community/commands.js | 2 +- bot/modules/community/messages.js | 2 +- bot/modules/community/scenes.js | 2 +- bot/modules/dispute/commands.js | 2 +- bot/modules/dispute/messages.js | 2 +- bot/modules/language/commands.js | 2 +- bot/modules/language/messages.js | 2 +- bot/modules/nostr/commands.js | 2 +- bot/modules/nostr/index.js | 2 +- bot/modules/orders/commands.js | 2 +- bot/modules/orders/index.js | 2 +- bot/modules/orders/messages.js | 2 +- bot/modules/orders/scenes.js | 2 +- bot/modules/orders/takeOrder.js | 2 +- bot/ordersActions.js | 2 +- bot/scenes.js | 2 +- bot/start.ts | 21 ++++++++++----------- bot/validations.ts | 2 +- ln/connect.ts | 8 ++++---- ln/hold_invoice.ts | 6 +++--- ln/info.ts | 6 +++--- ln/pay_request.js | 2 +- ln/subscribe_invoice.ts | 2 +- ln/subscribe_probe.js | 2 +- util/index.ts | 5 +++-- 26 files changed, 44 insertions(+), 44 deletions(-) diff --git a/bot/commands.js b/bot/commands.js index acfe66e7..175eae1a 100644 --- a/bot/commands.js +++ b/bot/commands.js @@ -19,7 +19,7 @@ const { const ordersActions = require('./ordersActions'); const { resolvLightningAddress } = require('../lnurl/lnurl-pay'); -const logger = require('../logger'); +const { logger } = require('../logger'); const waitPayment = async (ctx, bot, buyer, seller, order, buyerInvoice) => { try { diff --git a/bot/modules/community/commands.js b/bot/modules/community/commands.js index 83e29a68..1876914b 100644 --- a/bot/modules/community/commands.js +++ b/bot/modules/community/commands.js @@ -1,6 +1,6 @@ /* eslint-disable no-underscore-dangle */ // @ts-check -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { showUserCommunitiesMessage } = require('./messages'); const { Community, Order } = require('../../../models'); const { validateParams, validateObjectId } = require('../../validations'); diff --git a/bot/modules/community/messages.js b/bot/modules/community/messages.js index 61b398f9..85d3bfc4 100644 --- a/bot/modules/community/messages.js +++ b/bot/modules/community/messages.js @@ -1,4 +1,4 @@ -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { Community, PendingPayment } = require('../../../models'); exports.createCommunityWizardStatus = (i18n, state) => { diff --git a/bot/modules/community/scenes.js b/bot/modules/community/scenes.js index 612d2b86..81eb5f6b 100644 --- a/bot/modules/community/scenes.js +++ b/bot/modules/community/scenes.js @@ -1,5 +1,5 @@ const { Scenes } = require('telegraf'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { Community, User, PendingPayment } = require('../../../models'); const { isPendingPayment } = require('../../../ln'); const { isGroupAdmin, itemsFromMessage } = require('../../../util'); diff --git a/bot/modules/dispute/commands.js b/bot/modules/dispute/commands.js index 01ec8a6b..54b8cefd 100644 --- a/bot/modules/dispute/commands.js +++ b/bot/modules/dispute/commands.js @@ -6,7 +6,7 @@ const { } = require('../../validations'); const messages = require('./messages'); const globalMessages = require('../../messages'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const dispute = async ctx => { try { diff --git a/bot/modules/dispute/messages.js b/bot/modules/dispute/messages.js index 7999eb5b..40dc36bf 100644 --- a/bot/modules/dispute/messages.js +++ b/bot/modules/dispute/messages.js @@ -1,5 +1,5 @@ const { getDisputeChannel, getDetailedOrder } = require('../../../util'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); exports.beginDispute = async (ctx, initiator, order, buyer, seller) => { try { diff --git a/bot/modules/language/commands.js b/bot/modules/language/commands.js index c58e403c..0ce55db1 100644 --- a/bot/modules/language/commands.js +++ b/bot/modules/language/commands.js @@ -1,7 +1,7 @@ const path = require('path'); const fs = require('fs'); const { getLanguageFlag } = require('../../../util'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { showFlagsMessage } = require('./messages'); exports.setlang = async ctx => { diff --git a/bot/modules/language/messages.js b/bot/modules/language/messages.js index a0a10c4b..870abade 100644 --- a/bot/modules/language/messages.js +++ b/bot/modules/language/messages.js @@ -1,4 +1,4 @@ -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); exports.showFlagsMessage = async (ctx, flags, code) => { try { diff --git a/bot/modules/nostr/commands.js b/bot/modules/nostr/commands.js index 0f3d8db7..0861bdf5 100644 --- a/bot/modules/nostr/commands.js +++ b/bot/modules/nostr/commands.js @@ -1,5 +1,5 @@ const Nostr = require('nostr-tools'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const Config = require('./config'); exports.info = async ctx => { diff --git a/bot/modules/nostr/index.js b/bot/modules/nostr/index.js index d1fac01b..d3bad273 100644 --- a/bot/modules/nostr/index.js +++ b/bot/modules/nostr/index.js @@ -1,6 +1,6 @@ // @ts-check require('websocket-polyfill'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const Config = require('./config'); const { orderCreated } = require('./events'); const Commands = require('./commands'); diff --git a/bot/modules/orders/commands.js b/bot/modules/orders/commands.js index c04b4c82..1e9f4c63 100644 --- a/bot/modules/orders/commands.js +++ b/bot/modules/orders/commands.js @@ -1,5 +1,5 @@ // @ts-check -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { Community, Order } = require('../../../models'); const { isFloat } = require('../../../util'); const { diff --git a/bot/modules/orders/index.js b/bot/modules/orders/index.js index 42dabe52..bdf75edd 100644 --- a/bot/modules/orders/index.js +++ b/bot/modules/orders/index.js @@ -1,6 +1,6 @@ // @ts-check const { userMiddleware } = require('../../middleware/user'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const ordersActions = require('../../ordersActions'); const commands = require('./commands'); diff --git a/bot/modules/orders/messages.js b/bot/modules/orders/messages.js index e113b149..908eb6ec 100644 --- a/bot/modules/orders/messages.js +++ b/bot/modules/orders/messages.js @@ -3,7 +3,7 @@ const { sanitizeMD, getTimeToExpirationOrder, } = require('../../../util'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); exports.listOrdersResponse = async (orders, i18n) => { const tasks = orders.map(async order => { diff --git a/bot/modules/orders/scenes.js b/bot/modules/orders/scenes.js index 7e4e9065..a5ea0245 100644 --- a/bot/modules/orders/scenes.js +++ b/bot/modules/orders/scenes.js @@ -1,5 +1,5 @@ const { Scenes, Markup } = require('telegraf'); -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { getCurrency } = require('../../../util'); const ordersActions = require('../../ordersActions'); const { diff --git a/bot/modules/orders/takeOrder.js b/bot/modules/orders/takeOrder.js index 5e73a746..23c47b9d 100644 --- a/bot/modules/orders/takeOrder.js +++ b/bot/modules/orders/takeOrder.js @@ -1,5 +1,5 @@ // @ts-check -const logger = require('../../../logger'); +const { logger } = require('../../../logger'); const { Order } = require('../../../models'); const { deleteOrderFromChannel } = require('../../../util'); const messages = require('../../messages'); diff --git a/bot/ordersActions.js b/bot/ordersActions.js index 28360123..d36ebab5 100644 --- a/bot/ordersActions.js +++ b/bot/ordersActions.js @@ -10,7 +10,7 @@ const { getFee, getUserAge, } = require('../util'); -const logger = require('../logger'); +const { logger } = require('../logger'); const OrderEvents = require('./modules/events/orders'); diff --git a/bot/scenes.js b/bot/scenes.js index a4eb7559..86c1c6ce 100644 --- a/bot/scenes.js +++ b/bot/scenes.js @@ -5,7 +5,7 @@ const { waitPayment, addInvoice, showHoldInvoice } = require('./commands'); const { getCurrency, getUserI18nContext } = require('../util'); const messages = require('./messages'); const { isPendingPayment } = require('../ln'); -const logger = require('../logger'); +const { logger } = require('../logger'); const addInvoiceWizard = new Scenes.WizardScene( 'ADD_INVOICE_WIZARD_SCENE_ID', diff --git a/bot/start.ts b/bot/start.ts index 7546081a..77b28ac1 100644 --- a/bot/start.ts +++ b/bot/start.ts @@ -56,17 +56,16 @@ const { validateLightningAddress, } = require('./validations'); import * as messages from './messages'; -const { - attemptPendingPayments, - cancelOrders, - deleteOrders, - calculateEarnings, - attemptCommunitiesPendingPayments, - deleteCommunity, - nodeInfo, -} = require('../jobs'); -import logger from "../logger"; -import { ICommunity, IUsernameId } from '../models/community'; +import { attemptPendingPayments, + cancelOrders, + deleteOrders, + calculateEarnings, + attemptCommunitiesPendingPayments, + deleteCommunity, + nodeInfo +} from '../jobs'; +import { logger } from '../logger'; +import { IUsernameId } from '../models/community'; export interface MainContext extends Context { match: Array | null; diff --git a/bot/validations.ts b/bot/validations.ts index e6ce3881..408acce2 100644 --- a/bot/validations.ts +++ b/bot/validations.ts @@ -11,7 +11,7 @@ import * as messages from './messages'; import { Order, User, Community } from '../models'; const { isIso4217, isDisputeSolver } = require('../util'); const { existLightningAddress } = require('../lnurl/lnurl-pay'); -const logger = require('../logger'); +import { logger } from '../logger'; // We look in database if the telegram user exists, // if not, it creates a new user diff --git a/ln/connect.ts b/ln/connect.ts index f82b5c04..19c5e7df 100644 --- a/ln/connect.ts +++ b/ln/connect.ts @@ -1,7 +1,7 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as lightning from "lightning"; -import logger from "../logger"; +import fs from 'fs'; +import path from 'path'; +import lightning from 'lightning'; +import { logger } from '../logger'; const { authenticatedLndGrpc } = lightning; diff --git a/ln/hold_invoice.ts b/ln/hold_invoice.ts index 201d644c..82aea0eb 100644 --- a/ln/hold_invoice.ts +++ b/ln/hold_invoice.ts @@ -1,7 +1,7 @@ import { randomBytes, createHash } from 'crypto'; -import * as lightning from "lightning"; -import { lnd } from './connect' -import logger from "../logger"; +import lightning from 'lightning'; +import { lnd } from './connect'; +import { logger } from '../logger'; const createHoldInvoice = async (description: string, amount: number ) => { try { diff --git a/ln/info.ts b/ln/info.ts index 179fb82e..14ea89c8 100644 --- a/ln/info.ts +++ b/ln/info.ts @@ -1,6 +1,6 @@ -import * as lightning from "lightning"; -import { lnd } from './connect' -import logger from "../logger"; +import lightning from 'lightning'; +import { lnd } from './connect'; +import { logger } from '../logger'; export const getInfo = async () => { try { diff --git a/ln/pay_request.js b/ln/pay_request.js index 59fe6d38..df0b00f6 100644 --- a/ln/pay_request.js +++ b/ln/pay_request.js @@ -8,7 +8,7 @@ const { User, PendingPayment } = require('../models'); const lnd = require('./connect'); const { handleReputationItems, getUserI18nContext } = require('../util'); const messages = require('../bot/messages'); -const logger = require('../logger'); +const { logger } = require('../logger'); const payRequest = async ({ request, amount }) => { try { diff --git a/ln/subscribe_invoice.ts b/ln/subscribe_invoice.ts index 7700a479..30420b67 100644 --- a/ln/subscribe_invoice.ts +++ b/ln/subscribe_invoice.ts @@ -7,7 +7,7 @@ import { lnd } from "./connect"; import * as messages from '../bot/messages'; const ordersActions = require('../bot/ordersActions'); const { getUserI18nContext, getEmojiRate, decimalRound } = require('../util'); -import logger from "../logger"; +import { logger } from '../logger'; const subscribeInvoice = async (bot: Telegraf, id: string, resub: boolean) => { try { diff --git a/ln/subscribe_probe.js b/ln/subscribe_probe.js index 3bdc8fe7..4dc798bb 100644 --- a/ln/subscribe_probe.js +++ b/ln/subscribe_probe.js @@ -1,6 +1,6 @@ const { subscribeToProbeForRoute } = require('lightning'); const lnd = require('./connect'); -const logger = require('../logger'); +const { logger } = require('../logger'); const subscribeProbe = async (destination, tokens) => { try { diff --git a/util/index.ts b/util/index.ts index a9165729..6d617c4d 100644 --- a/util/index.ts +++ b/util/index.ts @@ -8,8 +8,9 @@ import { Telegram } from "telegraf/typings/core/types/typegram"; import axios from "axios"; import fiatJson from './fiat.json'; import languagesJson from './languages.json'; -import { Order, Community } from "../models"; -import logger from "../logger"; +import { Order, Community } from '../models'; +import { logger } from '../logger'; +import { MainContext } from '../bot/start'; const { I18n } = require('@grammyjs/i18n'); const languages: ILanguages = languagesJson; From 476a801d5c0ec849ada62638afeeb3f535505047 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 1 Nov 2023 13:33:23 +0330 Subject: [PATCH 4/6] fix(util/index): fix arg type & fn calls Typescript compilers in newer versions complain about when calling functions with named parameters, there is no argument interface for the deleteMessage method in Telegraf framework so I changed it, and there's a telegram argument with the wrong type. ``` util/index.ts:283:20 - error TS2554: Expected 2 arguments, but got 1. 283 await telegram.deleteMessage({chat_id: channel!, message_id: Number(order.tg_channel_message1!)}); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node_modules/telegraf/typings/telegram.d.ts:317:44 317 deleteMessage(chatId: number | string, messageId: number): Promise; ~~~~~~~~~~~~~~~~~ An argument for 'messageId' was not provided. Found 1 error in util/index.ts:283 ``` --- util/index.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/util/index.ts b/util/index.ts index 6d617c4d..d7a85cc0 100644 --- a/util/index.ts +++ b/util/index.ts @@ -4,7 +4,6 @@ import { IOrder } from "../models/order"; import { UserDocument } from "../models/user"; import { IFiatCurrencies, IFiat } from "./fiatModel"; import { ILanguage, ILanguages } from "./languagesModel"; -import { Telegram } from "telegraf/typings/core/types/typegram"; import axios from "axios"; import fiatJson from './fiat.json'; import languagesJson from './languages.json'; @@ -230,9 +229,9 @@ const secondsToTime = (secs: number) => { }; }; -const isGroupAdmin = async (groupId: string, user: UserDocument, telegram: Telegram) => { +const isGroupAdmin = async (groupId: string, user: UserDocument, telegram: MainContext['telegram']) => { try { - const member = await telegram.getChatMember({chat_id: groupId, user_id: Number(user.tg_id)}); + const member = await telegram.getChatMember(groupId, Number(user.tg_id)); if ( member && (member.status === 'creator' || member.status === 'administrator') @@ -261,9 +260,11 @@ const isGroupAdmin = async (groupId: string, user: UserDocument, telegram: Teleg } }; -const deleteOrderFromChannel = async (order: IOrder, telegram: Telegram) => { +const deleteOrderFromChannel = async (order: IOrder, telegram: MainContext['telegram']) => { try { let channel = process.env.CHANNEL; + if (channel === undefined) throw Error("CHANNEL not found, please check .env file") + if (order.tg_channel_message1 === undefined) throw Error("order.tg_channel_message1 was not found in DB") if (order.community_id) { const community = await Community.findOne({ _id: order.community_id }); if (!community) { @@ -279,7 +280,7 @@ const deleteOrderFromChannel = async (order: IOrder, telegram: Telegram) => { } } } - await telegram.deleteMessage({chat_id: channel!, message_id: Number(order.tg_channel_message1!)}); + await telegram.deleteMessage(channel, Number(order.tg_channel_message1)); } catch (error) { logger.error(error); } From d9e4720544f077315b825715e3e8803ead823331 Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Wed, 25 Oct 2023 16:36:44 +0330 Subject: [PATCH 5/6] fix: find & replace require with import While both import and require can be used to import modules in TypeScript, it is recommended to use import because it is part of the ES6 module system and provides better performance. --- app.ts | 2 +- bot/start.ts | 2 +- bot/validations.ts | 4 ++-- jobs/pending_payments.ts | 2 +- ln/subscribe_invoice.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app.ts b/app.ts index 498240f3..ab920927 100644 --- a/app.ts +++ b/app.ts @@ -6,7 +6,7 @@ import { connect as mongoConnect } from './db_connect' const { resubscribeInvoices } = require('./ln'); import { logger } from "./logger"; import { Telegraf } from "telegraf"; -const { delay } = require('./util'); +import { delay } from './util'; (async () => { process.on('unhandledRejection', e => { diff --git a/bot/start.ts b/bot/start.ts index 77b28ac1..7fddccfd 100644 --- a/bot/start.ts +++ b/bot/start.ts @@ -13,7 +13,7 @@ import { Dispute, Config, } from '../models'; -const { getCurrenciesWithPrice, deleteOrderFromChannel } = require('../util'); +import { getCurrenciesWithPrice, deleteOrderFromChannel } from '../util'; const { commandArgsMiddleware, stageMiddleware, diff --git a/bot/validations.ts b/bot/validations.ts index 408acce2..e10f8be2 100644 --- a/bot/validations.ts +++ b/bot/validations.ts @@ -9,8 +9,8 @@ const { parsePaymentRequest } = require('invoices'); const { ObjectId } = require('mongoose').Types; import * as messages from './messages'; import { Order, User, Community } from '../models'; -const { isIso4217, isDisputeSolver } = require('../util'); -const { existLightningAddress } = require('../lnurl/lnurl-pay'); +import { isIso4217, isDisputeSolver } from '../util'; +import { existLightningAddress } from '../lnurl/lnurl-pay'; import { logger } from '../logger'; // We look in database if the telegram user exists, diff --git a/jobs/pending_payments.ts b/jobs/pending_payments.ts index aaa750be..9691e9f2 100644 --- a/jobs/pending_payments.ts +++ b/jobs/pending_payments.ts @@ -5,7 +5,7 @@ import { Telegraf } from 'telegraf'; import { I18nContext } from '@grammyjs/i18n'; import { MainContext } from '../bot/start'; const { payRequest, isPendingPayment } = require('../ln'); -const { getUserI18nContext } = require('../util'); +import { getUserI18nContext } from '../util'; export const attemptPendingPayments = async (bot: Telegraf): Promise => { const pendingPayments = await PendingPayment.find({ diff --git a/ln/subscribe_invoice.ts b/ln/subscribe_invoice.ts index 30420b67..4f1d1ccf 100644 --- a/ln/subscribe_invoice.ts +++ b/ln/subscribe_invoice.ts @@ -6,7 +6,7 @@ const { payToBuyer } = require('./pay_request'); import { lnd } from "./connect"; import * as messages from '../bot/messages'; const ordersActions = require('../bot/ordersActions'); -const { getUserI18nContext, getEmojiRate, decimalRound } = require('../util'); +import { getUserI18nContext, getEmojiRate, decimalRound } from '../util'; import { logger } from '../logger'; const subscribeInvoice = async (bot: Telegraf, id: string, resub: boolean) => { From ff72fca7174cadd5757934b1a1a41a0cc2bc3dcd Mon Sep 17 00:00:00 2001 From: Mehrshad Date: Thu, 26 Oct 2023 15:05:22 +0330 Subject: [PATCH 6/6] fix(validations): fix named export As community may sometimes be null, I edited the isDisputeSolver function to accept null, so we don't have to do a null check over it. ``` bot/validations.ts:97:38 - error TS2345: Argument of type '(ICommunity & { _id: ObjectId; }) | null' is not assignable to parameter of type 'ICommunity'. Type 'null' is not assignable to type 'ICommunity'. 97 const isSolver = isDisputeSolver(community, user); ~~~~~~~~~ Found 1 error in bot/validations.ts:97 ``` --- bot/validations.ts | 7 +++---- util/index.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bot/validations.ts b/bot/validations.ts index e10f8be2..ab8729cd 100644 --- a/bot/validations.ts +++ b/bot/validations.ts @@ -6,7 +6,7 @@ import { IOrder } from "../models/order"; import { Telegraf } from "telegraf"; const { parsePaymentRequest } = require('invoices'); -const { ObjectId } = require('mongoose').Types; +import { Types } from 'mongoose'; import * as messages from './messages'; import { Order, User, Community } from '../models'; import { isIso4217, isDisputeSolver } from '../util'; @@ -94,7 +94,6 @@ const validateAdmin = async (ctx: MainContext, id?: string) => { if (user.default_community_id) community = await Community.findOne({ _id: user.default_community_id }); - if (community === null) throw Error("Community was not found in DB"); const isSolver = isDisputeSolver(community, user); if (!user.admin && !isSolver) @@ -593,7 +592,7 @@ const validateParams = async (ctx: MainContext, paramNumber: number, errOutputSt const validateObjectId = async (ctx: MainContext, id: string) => { try { - if (!ObjectId.isValid(id)) { + if (!Types.ObjectId.isValid(id)) { await messages.notValidIdMessage(ctx); return false; } @@ -647,7 +646,7 @@ const isBannedFromCommunity = async (user: UserDocument, communityId: string) => } }; -module.exports = { +export { validateSellOrder, validateBuyOrder, validateUser, diff --git a/util/index.ts b/util/index.ts index d7a85cc0..b22682fe 100644 --- a/util/index.ts +++ b/util/index.ts @@ -382,7 +382,7 @@ const getDetailedOrder = (i18n: I18nContext, order: IOrder, buyer: UserDocument, }; // We need to know if this user is a dispute solver for this community -const isDisputeSolver = (community: ICommunity, user: UserDocument) => { +const isDisputeSolver = (community: ICommunity | null, user: UserDocument) => { if (!community || !user) { return false; }