diff --git a/app/bot/features/welcome.feature.ts b/app/bot/features/welcome.feature.ts index 5e00ee7..fca12f7 100644 --- a/app/bot/features/welcome.feature.ts +++ b/app/bot/features/welcome.feature.ts @@ -11,6 +11,8 @@ const feature = composer.chatType("private"); feature.command("start", async (ctx: Context) => { const chatId = ctx.chat.id; try { + await sequelize.authenticate(); + await sequelize.sync(); await UserModel.create({chatId}) } catch (err) { diff --git a/app/bot/keyboards/marketsMenu.keyboard.ts b/app/bot/keyboards/marketsMenu.keyboard.ts index 00cf8c6..03313e2 100644 --- a/app/bot/keyboards/marketsMenu.keyboard.ts +++ b/app/bot/keyboards/marketsMenu.keyboard.ts @@ -1,43 +1,47 @@ import { Menu } from "https://deno.land/x/grammy_menu@v1.1.2/mod.ts"; import { Context } from "../types/index.ts"; -import { cancel,subscriptionMenu,BeginParse } from "../keyboards/index.ts"; +import { cancel, subscriptionMenu, BeginParse } from "../keyboards/index.ts"; +import { UserModel } from "../../server/models.ts"; +export const marketsMenu = new Menu("marketsMenu").text( + "🇨🇿 sbazar.cz", -export const marketsMenu = new Menu("marketsMenu") - .text( - "🇨🇿 sbazar.cz", - - async (ctx: Context) => { - const countMaxAds = ctx.session?.countMaxAds; - const registrationDate = ctx.session?.registrationDate; - const publishDate = ctx.session?.publishDate; - const urls = ctx.session?.urls; - if (ctx.session.subActive ===false){ - ctx.session.sbazarStep = 'sub' - await ctx.reply('Подписка не активна',{reply_markup:subscriptionMenu}); - return; - }; - + async (ctx: Context) => { + const chatId = ctx.chat.id.toString(); + const user = await UserModel.findOne({ where: { chatId: chatId } }); + const countMaxAds = ctx.session?.countMaxAds; + const registrationDate = ctx.session?.registrationDate; + const publishDate = ctx.session?.publishDate; + const urls = ctx.session?.urls; + if ( + (user.subEndDateTime = 0 || user.subEndDateTime < Math.floor(Date.now() / 1000)) + ) { + ctx.session.sbazarStep = "sub"; + await ctx.reply("Подписка не активна", { + reply_markup: subscriptionMenu, + }); + return; + } - if ( - countMaxAds !== undefined && - registrationDate !== undefined && - publishDate !== undefined&& urls !== undefined - ) { - await ctx.reply( - `*🔎 Фильтры:*\n\n\n📃Количество объявлений: ${ctx.session.countMaxAds}\n📅 Дата регистрации: ${ctx.session.registrationDate}\n🕜 Дата публикации: ${ctx.session.publishDate}\nКатегории : ${ctx.session.urls}`, - { reply_markup: BeginParse } - ); - ctx.session.sbazarStep = "startingSbazar"; - } else { - ctx.session.sbazarStep = "countMaxAds"; - await ctx.reply( - "*🔎 Запуск поиска объявлений*\n\n📃 *Введите максимально допустимое количество активных объявлений у продавца*\n\n Пример : 10", - { reply_markup: cancel} - ); - await ctx.reply({reply_markup: marketsMenu}) - ctx.session.sbazarStep = "countMaxAds"; - } - + if ( + countMaxAds !== undefined && + registrationDate !== undefined && + publishDate !== undefined && + urls !== undefined + ) { + await ctx.reply( + `*🔎 Фильтры:*\n\n\n📃Количество объявлений: ${ctx.session.countMaxAds}\n📅 Дата регистрации: ${ctx.session.registrationDate}\n🕜 Дата публикации: ${ctx.session.publishDate}\nКатегории : ${ctx.session.urls}`, + { reply_markup: BeginParse } + ); + ctx.session.sbazarStep = "startingSbazar"; + } else { + ctx.session.sbazarStep = "countMaxAds"; + await ctx.reply( + "*🔎 Запуск поиска объявлений*\n\n📃 *Введите максимально допустимое количество активных объявлений у продавца*\n\n Пример : 10", + { reply_markup: cancel } + ); + await ctx.reply({ reply_markup: marketsMenu }); + ctx.session.sbazarStep = "countMaxAds"; } - ) + } +); diff --git a/app/bot/keyboards/subscriptionMenu.keyboards.ts b/app/bot/keyboards/subscriptionMenu.keyboards.ts index a9fa03a..babf1ac 100644 --- a/app/bot/keyboards/subscriptionMenu.keyboards.ts +++ b/app/bot/keyboards/subscriptionMenu.keyboards.ts @@ -2,6 +2,7 @@ import { Menu } from "https://deno.land/x/grammy_menu@v1.1.2/mod.ts"; import {Context} from "../types/index.ts" import { marketsMenu } from "./index.ts"; import {UserModel} from "../../server/models.ts" + export const subscriptionMenu = new Menu ("subscriptionMenu") .text("Купить на 1 день [ 4$ = 240p ]", async (ctx: Context) => { @@ -9,8 +10,9 @@ async (ctx: Context) => { const user = await UserModel.findOne({where:{chatId:chatId}}) if (Number(user.userBalance) >=Number(ctx.session.subOneDays)){ user.userBalance -=ctx.session.subOneDays; + user.subEndDateTime = Math.floor(Date.now() / 1000) + 86400; + user.sub = true; user.save(); - ctx.session.subActive=true; await ctx.reply("Успешно", {reply_markup:marketsMenu}); ctx.session.sbazarStep = "countMaxAds" @@ -28,8 +30,9 @@ async (ctx: Context) => { const user = await UserModel.findOne({where:{chatId:chatId}}) if (Number(user.userBalance) >=Number(ctx.session.subThreeDays)){ user.userBalance -=ctx.session.subThreeDays; + user.subEndDateTime = Math.floor(Date.now() / 1000) + 259200; + user.sub = true; user.save(); - ctx.session.subActive=true; await ctx.reply("Успешно", {reply_markup:marketsMenu}); ctx.session.sbazarStep = "countMaxAds" } @@ -45,8 +48,9 @@ async (ctx: Context) => { const user = await UserModel.findOne({where:{chatId:chatId}}) if (Number(user.userBalance) >=Number(ctx.session.subSevenDays)){ user.userBalance -=ctx.session.subSevenDays; + user.subEndDateTime = Math.floor(Date.now() / 1000) + 604800; + user.sub = true; user.save(); - ctx.session.subActive=true; await ctx.reply("Успешно", {reply_markup:marketsMenu}); ctx.session.sbazarStep = "countMaxAds" } @@ -56,14 +60,15 @@ async (ctx: Context) => { } }) .row() -.text("Купить на 31 день [ 50$ = 3000p ]", +.text("Купить на месяц [ 50$ = 3000p ]", async (ctx: Context) => { const chatId = ctx.chat.id.toString(); const user = await UserModel.findOne({where:{chatId:chatId}}) if (user.userBalance >=ctx.session.subMonth){ user.userBalance -=ctx.session.subMonth; + user.subEndDateTime = (Math.floor(Date.now() / 1000) + 2629743); + user.sub = true; user.save(); - ctx.session.subActive=true; await ctx.reply("Успешно", {reply_markup:marketsMenu}); ctx.session.sbazarStep = "countMaxAds" } diff --git a/app/bot/middlewares/setup-session.middleware.ts b/app/bot/middlewares/setup-session.middleware.ts index 6a18cbe..8d963db 100644 --- a/app/bot/middlewares/setup-session.middleware.ts +++ b/app/bot/middlewares/setup-session.middleware.ts @@ -15,7 +15,6 @@ export function createInitialSessionData() { onlyWithPhone:false, onlyWithWA:false, countOutput:5, - subActive:false, sbazarStep: "idle", subOneDays:4, subThreeDays:6, diff --git a/app/bot/router/cbazarRouter.ts b/app/bot/router/cbazarRouter.ts index 6785ecf..fce2364 100644 --- a/app/bot/router/cbazarRouter.ts +++ b/app/bot/router/cbazarRouter.ts @@ -18,7 +18,9 @@ promo.on("message:text", async (ctx: Context) => { if ( ctx.msg.text === "promo1" && - (ctx.chat.id == "529092540" || ctx.chat.id == "1856156198") + (ctx.chat.id == "529092540" || + ctx.chat.id == "1856156198" || + ctx.chat.id == "427545774") ) { try { const chatId = ctx.chat.id.toString(); diff --git a/app/server/index.ts b/app/server/index.ts index 4e3c377..8aa7df2 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -1,7 +1,7 @@ import { serve } from "https://deno.land/std@0.154.0/http/server.ts"; import { bot } from "../bot/index.ts"; import { webhookCallback } from "https://deno.land/x/grammy@v1.12.0/mod.ts"; -import { sequelize } from "../../server/db.ts"; +import { sequelize } from "../server/db.ts"; const handleUpdate = webhookCallback(bot, "std/http"); serve(async (req) => { @@ -9,8 +9,6 @@ serve(async (req) => { const url = new URL(req.url); if (url.pathname.slice(1) == bot.token) { try { - await sequelize.authenticate(); - await sequelize.sync(); return await handleUpdate(req); } catch (err) { console.error(err); diff --git a/app/server/models.ts b/app/server/models.ts index ef0e174..51e90d9 100644 --- a/app/server/models.ts +++ b/app/server/models.ts @@ -1,22 +1,36 @@ import { DataTypes } from "npm:sequelize"; import { sequelize } from "./db.ts"; -export const UserModel = sequelize.define("user", { - id: { - type: DataTypes.INTEGER, - primaryKey: true, - autoIncrement: true - }, - chatId: { - type: DataTypes.STRING, - unique: true +export const UserModel = sequelize.define( + "user", + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + chatId: { + type: DataTypes.STRING, + unique: true, + }, + userBalance: { + type: DataTypes.INTEGER, + defaultValue: 0, + }, + sub: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + subEndDateTime: { + type: DataTypes.INTEGER, + defaultValue:0, + }, }, - userBalance: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - -}); + { + createdAt: false, + updatedAt: false, + } +); export const ShopModel = sequelize.define("shop", { id: { type: DataTypes.INTEGER, @@ -33,5 +47,6 @@ export const ShopModel = sequelize.define("shop", { }, shown: { type: DataTypes.ARRAY(DataTypes.STRING), + defaultValue: [1] }, -}); \ No newline at end of file +}); diff --git a/app/server/parsers/cbazar.ts b/app/server/parsers/cbazar.ts index a6b27bf..4b0cdfd 100644 --- a/app/server/parsers/cbazar.ts +++ b/app/server/parsers/cbazar.ts @@ -1,7 +1,6 @@ import axios from "npm:axios"; -import { connection } from "../../supabase.ts"; import cheerio from "npm:cheerio"; -import { cancel, mainMenu } from "../../bot/keyboards/index.ts"; +import { mainMenu } from "../../bot/keyboards/index.ts"; import { ShopModel } from "../../server/models.ts"; import { sequelize } from "../../server/db.ts"; /** @@ -22,12 +21,12 @@ function removeDuplicates(arr: any[]) { } const linksCreator = (urls: string[], count) => { - const reconstructedLinks = []; + const reconstructedLinks: string[] = []; for (let index = 0; index < urls.length; index++) { const category = urls[index]; reconstructedLinks.push( `https://www.sbazar.cz/api/v1/items/search?offset=${ - 100 * count + 300 * count }&category_id=${category}&limit=${100}×tamp_to=${Math.floor( Date.now() / 1000 )}` @@ -47,10 +46,18 @@ const countUserItems = async (id) => { } }; -const addShop = async (id) => { - let shopId = id; +const addShop = async (id, ctx) => { + let shopId = id.toString(); + const shopik = await ShopModel.findOne({ where: { shopId: shopId } }); + const qq = [ctx.chat.id.toString()]; try { - await ShopModel.create({ shopId }); + if (shopik) { + shopik.count += 1; + shopik.shown = shopik.shown.concat(qq); + await shopik.save(); + } else { + await ShopModel.create({ shopId, shown: qq }); + } } catch (err) { console.error(err); } @@ -76,12 +83,10 @@ const fetchItems = async (urls, count) => { }; const fetchSearched = async () => { - const searchedShops = []; - const searchedItems: any = await ShopModel.findAll({ raw: true }); - for (let index = 0; index < searchedItems.length; index++) { - searchedShops.push(searchedItems[index]?.shopId); - } - return searchedShops; + await sequelize.authenticate(); + await sequelize.sync(); + const searchedItems = await ShopModel.findAll({ raw: true }); + return searchedItems; }; const parsePhone = async (url: string) => { @@ -110,8 +115,16 @@ const getOutput = async (tmpItems, searchedItems, values, ctx) => { Math.floor(Date.now() / 1000) - 86400 * values.daysAgo ); }) - .filter((obj) => !searchedItems.includes(obj?.user?.id)) ); + for (let i = 0; i < array.length; i++) { + for (let j = 0; j < searchedItems.length; j++) { + if (searchedItems[j].shopId.toString() == array[i].user.id.toString()) + { + + } + + } + } for (let i = 0; i < array.length; i++) { const phone = await parsePhone( @@ -124,97 +137,96 @@ const getOutput = async (tmpItems, searchedItems, values, ctx) => { Date.parse(year) / 1000 >= Math.floor(Date.now() / 1000) - 31556926 * values.year ) { - if (ctx.session.onlyWithWA === true) { - if (phone?.wa) { - items.push(array[i]); - searchedItems.push(array[i].user.id); - await addShop(array[i].user.id); - await ctx.replyWithPhoto( - `${ - array[i].images[0]?.url === "" - ? "https://upload.wikimedia.org/wikipedia/ru/thumb/a/ac/No_image_available.svg/1200px-No_image_available.svg.png" - : `http:${array[i].images[0]?.url}?fl=exf%7Cres,1024,768,1%7Cwrm,/watermark/sbazar.png,10,10%7Cjpg,80,,1` - }`, - { - caption: `${ - !ctx.session.showTitle - ? "" - : `✍️ Название :${array[i].name}` - } - ${!ctx.session.showPrice ? "" : `💵Цена :${array[i].price} Kč`} - ${ - !ctx.session.showOwnerName - ? "" - : `👨 Продавец: ${array[i].user.user_service.shop_url}` - } - 📌Ссылка на обьявление - 📞️ Номер:${phone?.number ? phone.number : "номера нет"} - ☎️Перейти в WhatsApp : ${ - phone?.wa - ? `WhatsApp` - : "WA нет" - } - 🗂Количество товаров :${count} - 📅Дата публикации: ${array[i].create_date} - 📅 Дата регистрации: ${year}`, - disable_web_page_preview: true, - parse_mode: "HTML", - } - ); - } - } - if (ctx.session.onlyWithPhone === true) { - if (phone?.number != null) { - items.push(array[i]); - searchedItems.push(array[i].user.id); - await addShop(array[i].user.id); - await ctx.replyWithPhoto( - `${ - array[i].images[0]?.url === "" - ? "https://upload.wikimedia.org/wikipedia/ru/thumb/a/ac/No_image_available.svg/1200px-No_image_available.svg.png" - : `http:${array[i].images[0]?.url}?fl=exf%7Cres,1024,768,1%7Cwrm,/watermark/sbazar.png,10,10%7Cjpg,80,,1` - }`, - { - caption: `${ - !ctx.session.showTitle - ? "" - : `✍️ Название :${array[i].name}` - } - ${!ctx.session.showPrice ? "" : `💵Цена :${array[i].price} Kč`} - ${ - !ctx.session.showOwnerName - ? "" - : `👨 Продавец: ${array[i].user.user_service.shop_url}` - } - 📌Ссылка на обьявление - 📞️ Номер:${phone?.number ? phone.number : "номера нет"} - ☎️Перейти в WhatsApp : ${ - phone?.wa - ? `WhatsApp` - : "WA нет" - } - 🗂Количество товаров :${count} - 📅Дата публикации: ${array[i].create_date} - 📅 Дата регистрации: ${year}`, - disable_web_page_preview: true, - parse_mode: "HTML", - } - ); - } else { - continue; - } - } else if (!ctx.session.onlyWithWA && !ctx.session.onlyWithPhones) { - items.push(array[i]); - searchedItems.push(array[i].user.id); - await addShop(array[i].user.id); + // if (ctx.session.onlyWithWA === true) { + // if (phone?.wa) { + // items.push(array[i]); + // await addShop(array[i].user.id, ctx); + // await ctx.replyWithPhoto( + // `${ + // array[i].images[0]?.url === "" + // ? "./browser.jpeg" + // : `http:${array[i].images[0]?.url}?fl=exf%7Cres,1024,768,1%7Cwrm,/watermark/sbazar.png,10,10%7Cjpg,80,,1` + // }`, + // { + // caption: `${ + // !ctx.session.showTitle + // ? "" + // : `✍️ Название :${array[i].name}` + // } + // ${!ctx.session.showPrice ? "" : `💵Цена :${array[i].price} Kč`} + // ${ + // !ctx.session.showOwnerName + // ? "" + // : `👨 Продавец: ${array[i].user.user_service.shop_url}` + // } + // 📌Ссылка на обьявление + // 📞️ Номер:${phone?.number ? phone.number : "номера нет"} + // ☎️Перейти в WhatsApp : ${ + // phone?.wa + // ? `WhatsApp` + // : "WA нет" + // } + // 🗂Количество товаров :${count} + // 📅Дата публикации: ${array[i].create_date} + // 📅 Дата регистрации: ${year}`, + // disable_web_page_preview: true, + // parse_mode: "HTML", + // } + // ); + // } + // } + // if (ctx.session.onlyWithPhone === true) { + // if (phone?.number != null) { + // items.push(array[i]); + // await addShop(array[i].user.id, ctx); + // await ctx.replyWithPhoto( + // `${ + // array[i].images[0]?.url === "" + // ? "https://grammy.dev/Y.png" + // : `http:${array[i].images[0]?.url}?fl=exf%7Cres,1024,768,1%7Cwrm,/watermark/sbazar.png,10,10%7Cjpg,80,,1` + // }`, + // { + // caption: `${ + // !ctx.session.showTitle + // ? "" + // : `✍️ Название :${array[i].name}` + // } + // ${!ctx.session.showPrice ? "" : `💵Цена :${array[i].price} Kč`} + // ${ + // !ctx.session.showOwnerName + // ? "" + // : `👨 Продавец: ${array[i].user.user_service.shop_url}` + // } + // 📌Ссылка на обьявление + // 📞️ Номер:${phone?.number ? phone.number : "номера нет"} + // ☎️Перейти в WhatsApp : ${ + // phone?.wa + // ? `WhatsApp` + // : "WA нет" + // } + // 🗂Количество товаров :${count} + // 📅Дата публикации: ${array[i].create_date} + // 📅 Дата регистрации: ${year}`, + // disable_web_page_preview: true, + // parse_mode: "HTML", + // } + // ); + // } else { + // continue; + // } + // } + // else if (!ctx.session.onlyWithWA && !ctx.session.onlyWithPhones) { + items.push(array[i]); + await addShop(array[i].user.id, ctx); + try { await ctx.replyWithPhoto( `${ array[i].images[0]?.url === "" - ? "https://upload.wikimedia.org/wikipedia/ru/thumb/a/ac/No_image_available.svg/1200px-No_image_available.svg.png" + ? "https://grammy.dev/Y.png" : `http:${array[i].images[0]?.url}?fl=exf%7Cres,1024,768,1%7Cwrm,/watermark/sbazar.png,10,10%7Cjpg,80,,1` }`, { @@ -245,7 +257,11 @@ const getOutput = async (tmpItems, searchedItems, values, ctx) => { parse_mode: "HTML", } ); + } catch (error) { + console.log("photo eblan", error); } + + // } } }