const { BufferJSON, WA_DEFAULT_EPHEMERAL, generateWAMessageFromContent, proto, generateWAMessageContent, generateWAMessage, prepareWAMessageMedia, areJidsSameUser, getContentType } = require("@adiwajshing/baileys");
const fs = require("fs");
const util = require("util");
const chalk = require("chalk");
const https = require('https');
const { Configuration, OpenAIApi } = require("openai");
const gtts = require('better-node-gtts').default;
const moment = require('moment');
let setting = require("./key.json");
const path = require('path');

let unlink = util.promisify(fs.unlinkSync)
const path2 = require('path')
const nodemailer = require('nodemailer'); 

const { ownerNumber } = setting = require('./key.json');
const sessions = new Map()
const instamojo  = require("instamojo-payment-nodejs");
instamojo.isSandboxMode(false); // For testing
instamojo.setKeys('c6c3aa8560d6047e700a67e444d1fe0e', 'c6ff419a008d26a6afcb9aff0036cad5');
if (!fs.existsSync("limits.json")) {
    fs.writeFileSync("limits.json", JSON.stringify({}));
}
const databasePath = path.join(__dirname, 'subscription-database.json');

function Checker(userId,m,client){
    if (isVerified(userId)){
        if (Premium(userId)) {
            return true
        } else if (Limited(userId,m,client)) {
            return true
        }else {
            return false
        }
  
    } else {
        const templateMessage = {
            text: '*πŸ“§βœ… Verify your email now!*\n\nTo complete your registration, Please type *verify* to verify your email address.\n\nπŸ‘‰ Only Gmail and Outlook accounts are supported.',
            footer: 'Note: Only Gmail and Outlook are Valid',
            viewOnce: true,
        };
        client.sendMessage(m.sender,templateMessage)
        
        return false
    }
};


function Limited(userId,m,client) {
    const WhiteListUsers = [916206225290, 1555922408]; // whitelisted users
        let maximumRequestLimit = 30;
        if (!fs.existsSync("limits.json")) {
            fs.writeFileSync("limits.json", JSON.stringify({}));
        }
        let limits =  JSON.parse(fs.readFileSync("limits.json", "utf8"));
        if (!limits[userId]) {
            limits[userId] = {
            requests: 0,
            };
        }
        const limit = limits[userId];
        if (WhiteListUsers.includes(userId)) {
            return true
        } else if (limit.requests >= maximumRequestLimit)  {
            const templateMessage = {
                            text: '*πŸ›‘πŸ€š Limits Reached!*\n\nTo continue accessing our services without any restrictions, subscribe now for unlimited access.\n*πŸ’¬ Type "sub" to subscribe.*',
                            footer: 'Subscribe?',
                            viewOnce: true,
                        };
            client.sendMessage(m.sender,templateMessage)
            return false
        } else {
            limit.requests++;
            fs.writeFileSync("limits.json", JSON.stringify(limits));
            return true
        }
};


function Premium(userId) {
    let db = {};
    
    try {
        const data = fs.readFileSync(databasePath, 'utf8');
        db = JSON.parse(data);
    } catch (error) {
        console.error(error);
        fs.writeFileSync(databasePath, JSON.stringify(db, null, 2), 'utf8');
    }
    const exp = new Date();
    exp.setDate(exp.getDate() - 365);
    struser = userId.toString()
    if (!db.hasOwnProperty(userId)) {
        db[userId] = {
            userId : userId,
            expiryd : exp
        };
        fs.writeFileSync(databasePath, JSON.stringify(db), 'utf8');
    }
    const database = JSON.parse(fs.readFileSync(databasePath, 'utf8'));
    const subscription = database[userId].expiryd
    if (new Date(subscription) > new Date()) {
        return true;;
    } else {
        return false
    }
}


function generateOTP() {
  return Math.floor(Math.random() * 9000) + 1000;
}

async function sendOTP(email, otp) {
  const transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 587,
    secureProtocol: 'TLSv1_2_method',
    auth: {
      user: "[email protected]",
      pass: "kenmsqdgsntchext"
    },
  });

  const mailOptions = {
      from: '[email protected]',
      to: email,
      subject: 'Your OTP for the Harshitethic BOT',
      html: `<h2>Your verification code for Whatsapp BOT is : ${otp} </h2>`,
  };

  const info = await transporter.sendMail(mailOptions);
  console.log(`OTP sent to ${email}: ${otp}`);
}

function isVerified(email,userId) {
    if (!fs.existsSync('user-database.txt')) {
         fs.writeFileSync('user-database.txt',"");
    }
    const data = fs.readFileSync('user-database.txt', 'utf8');
    const lines = data.split('\n');
    for (let i = 0; i < lines.length; i++) {
        if (lines[i].startsWith(userId + ',')) {
            const parts = lines[i].split(':');
            return parts[1] === 'verified';
        } else if (lines[i].startsWith(email + ',')) {
            const parts = lines[i].split(':');
            return parts[1] === 'verified';
        }
    }
  return false;
}

async function verifyEmail(email) {
  const otp = generateOTP();
  await sendOTP(email, otp);
  return otp;
}


function addVerifiedUser(email,chatidd) {
  fs.appendFileSync('user-database.txt', `${chatidd},${email}:verified\n`);
}
module.exports = harshit = async (client, m, chatUpdate, store) => {
    try {
      var body =
            m.mtype === "conversation"
                ? m.message.conversation
                : m.mtype == "imageMessage"
                    ? m.message.imageMessage.caption
                    : m.mtype == "videoMessage"
                        ? m.message.videoMessage.caption
                        : m.mtype == "extendedTextMessage"
                            ? m.message.extendedTextMessage.text
                            : m.mtype == "buttonsResponseMessage"
                                ? m.message.buttonsResponseMessage.selectedButtonId
                                : m.mtype == "listResponseMessage"
                                    ? m.message.listResponseMessage.singleSelectReply.selectedRowId
                                    : m.mtype == "templateButtonReplyMessage"
                                        ? m.message.templateButtonReplyMessage.selectedId
                                        : m.mtype === "messageContextInfo"
                                            ? m.message.buttonsResponseMessage?.selectedButtonId || m.message.listResponseMessage?.singleSelectReply.selectedRowId || m.text
                                            : "";
        var budy = typeof m.text == "string" ? m.text : ""
        var prefix = /^[\\/!#.]/gi.test(body) ? body.match(/^[\\/!#.]/gi) : "/";
        let isCmd2 = true;
        if (budy.includes("-")) {
            isCmd2 = false;
        }

        // This code block image and video messages
        if ((m.mtype == "imageMessage") || (m.mtype == "videoMessage")) {
            return false;
        }


         // This code call stop and start function
        let cmdFilters = await handleStopStart(m.text, m.chat);
        if (!cmdFilters) {
            return false;
        }

        const command = body.replace(prefix, "").trim().split(/ +/).shift().toLowerCase();
        const args = body.trim().split(/ +/).slice(1);
        const pushname = m.pushName;
        const botNumber = await client.decodeJid(client.user.id);
        const itsMe = m.sender == botNumber ? true : false;
        let text = (q = args.join(""));
        const arg = budy.trim().substring(budy.indexOf(" ") + 1);
        const arg1 = arg.trim().substring(arg.indexOf(" ") + 1);
        const from = m.chat;
        const reply = m.reply;
        const sender = m.sender;
        const userId = m.sender.split('@')[0]
        const mek = chatUpdate.messages[0];
       
// user block
// const prefixes = ["212"];
// if (prefixes.some(p => m.sender.startsWith(p))) return client.updateBlockStatus(m.sender, "block");
// user block end

        
        const { jid } = chatUpdate
        let sessionMap = sessions.get(jid)
        if (!sessionMap) {
            sessionMap = new Map()
            sessions.set(jid, sessionMap)
        }
        let sessionID = sender
        let session = sessionMap.get(sessionID)

        const isOwner = ownerNumber == sender ? true : ["[email protected]"].includes(sender) ? true : false;
        const color = (text, color) => {
            return !color ? chalk.green(text) : chalk.keyword(color)(text);
        };
        

        let image_prompt =
            "Gorgeous digital painting with sober colours amazing art mesmerizing, captivating, artstation 3, realistic, render materials, of " + text
            ;
      
        

        // Group
        const groupMetadata = m.isGroup ? await client.groupMetadata(m.chat).catch((e) => { }) : "";
        const groupName = m.isGroup ? groupMetadata.subject : "";

        const wizard = {
  start: async (client, session,text,) => {
    const orderId = Math.floor(Math.random() * 1000000).toString();
    const subscriptionPlan = {
      name: 'Monthly Subscription',
      amount: 99.00,
      duration: 30 
    };
    session.plan = subscriptionPlan
    const paymentData = {
      purpose: "For Whatsapp Bot",
      amount: subscriptionPlan.amount,
      currency: "INR",
    };
    
    const paymentLink = instamojo.PaymentData(paymentData);
    const response = await instamojo.createNewPaymentRequest(paymentLink);
    const templateMessage = {
      text: "Please make the payment by clicking on this link: " + response.payment_request.longurl,
      viewOnce: true,
    };
    await client.sendMessage(session.sender, templateMessage)
    session.txnid = response.payment_request.id
    
    session.tries = 0;
    return 'step1'
  },
          
            step1: async (client, session,text) => {
                const tries = session.tries || 0;
                const userId = session.userId
                const paymentId = (session.txnid).toString();
                const payment = await instamojo.getPaymentRequestStatus(paymentId);
                const database = JSON.parse(fs.readFileSync(databasePath, 'utf8'));
                try {
                    if (payment.payment_request.status === 'Completed') {
                        const userSubscription = database[userId]
                        if (userSubscription && new Date(userSubscription.expiryd) < new Date()) {
                            const subscriptionPlan = session.plan;
                            const expiryDate = new Date();
                            expiryDate.setDate(expiryDate.getDate() + subscriptionPlan.duration);
                            userSubscription.expiryd = expiryDate;
                            fs.writeFileSync(databasePath, JSON.stringify(database), 'utf8');
                        } else {
                            await m.reply(`*Congratulations! πŸŽ‰*
If your payment is completed, your subscription is now enabled.

*Here's what you need to know:*

Your payment ID :\n${session.txnid}

πŸ‘‰ If the system didn't capture your payment, don't worry. Your subscription will be activated within one minute. ⏰
πŸ‘‰ However, if your subscription doesn't activate automatically, you can type "/admin" and share the payment ID and screenshot. Our team will assist you. πŸ’ͺ

`)
                            sessionMap.delete(sessionID)
                            return 
                        }
                        await m.reply(`πŸŽ‰ Congratulations πŸŽ‰\n\n Your Payment has been Confirmed Welcome to the family\n\nYour subscription is valid till ` + new Date(subscription).toDateString() + '.')
                        sessionMap.delete(sessionID)
                        return 
                    } else if (tries < 5) {
                        await m.reply(`We are currently verifying your payment.

Kindly allow us 2-3 minutes before reaching out again. 
You may retry the transaction if the transaction is failed. (Attempt ${tries + 1}/5) β³πŸ’³`)
                        session.tries = tries + 1;
                        return 'step1'
                    } else {
                        await m.reply(`Maximum number of Attempts exceeded. Please start again to Subscribe. if you think this is a mistake reach out to admin \n\nYour Payment ID :\n${session.txnid}`)
                        sessionMap.delete(sessionID)
                        return 
                    }
                } catch {
                    if (tries < 5) {
                        await m.reply(`We are currently verifying your payment.

Kindly allow us 2-3 minutes before reaching out again. 
You may retry the transaction if the transaction is failed. (Attempt ${tries + 1}/5) β³πŸ’³`)
                        session.tries = tries + 1;
                        return 'step1'
                    } else {
                        await m.reply('Maximum number of tries exceeded. Please start again to Subscribe.')
                        sessionMap.delete(sessionID)
                        return 
                    }
                }
            },
            
          
            step2: async (client, session,text3) => {
                const userId =  session.userId
                if (isVerified(userId)) {
                    m.reply("Your email is Already Verified")
                    sessionMap.delete(sessionID)
                    return 
                } else {
                    m.reply("Please enter your email address")
                    session.try = 0;
                    return 'step3'
                }
                
            },
          
            step3: async (client, session,text3) => {
                const userId =  session.userId
                const tries  =  session.try
                
                if (text3.includes('@gmail.com') || text3.includes('@outlook.com')) {
                    const email = text3.toLowerCase();
                    if (isVerified(email,userId)) {
                        m.reply('Your Email is already verified')
                        sessionMap.delete(sessionID)
                        return
                    } else {
                        const otp = await verifyEmail(email);
                        m.reply('An OTP has been Sent to your Email Address!')
                        session.email = email;
                        session.otp = otp;
                        return 'end'
                    }
                }else {
                    m.reply('Invalid email. Try using Gmail or Outlook for email verification .')
                    sessionMap.delete(sessionID)
                    return

                }
            },
          
            end: async (client, session,text3) => {
                const userId =  session.userId
                if (/^\d{4}$/.test(text3) && session.email && session.otp) {
                    const enteredOtp = text3;
                    const email = session.email;
                    const otp = session.otp;
                    if (enteredOtp == otp) {
                        addVerifiedUser(email,userId);
                        m.reply('πŸ“©βœ…πŸ’¬ *Email Verified*\nYou can start using!')
                        sessionMap.delete(sessionID)
                        return
                    } else {
                        m.reply('*Invalid OTP, Please Try Again*');
                        sessionMap.delete(sessionID)
                        return
                    }
                    
                } else {
                    m.reply('*Invalid OTP, Please Try Again*');
                    sessionMap.delete(sessionID)
                    return
                }
                
            },
          };
        

        // Push Message To Console
        let argsLog = budy.length > 30 ? `${q.substring(0, 30)}...` : budy;

        if (isCmd2 && !m.isGroup) {
            console.log(chalk.black(chalk.bgWhite("[ LOGS ]")), color(argsLog, "turquoise"), chalk.magenta("From"), chalk.green(pushname), chalk.yellow(`[ ${m.sender.replace("@s.whatsapp.net", "")} ]`));
        } else if (isCmd2 && m.isGroup) {
            console.log(
                chalk.black(chalk.bgWhite("[ LOGS ]")),
                color(argsLog, "turquoise"),
                chalk.magenta("From"),
                chalk.green(pushname),
                chalk.yellow(`[ ${m.sender.replace("@s.whatsapp.net", "")} ]`),
                chalk.blueBright("IN"),
                chalk.green(groupName)
            );
        }

        if (isCmd2) {

            switch (command) {
                case "help":
                case "menu":
                    m.reply(`MENU TEXT GOES HERE`
                    )
                    break;
                
               
                // Image Start

                case "img": case "ai-img": case "image": case "images": case "draw": case "photo":
                    if (Checker(userId,m,client)) {
                    try {
                        const configuration = new Configuration({
                            apiKey: setting.keyopenai,
                        });
                        const openai = new OpenAIApi(configuration);
                        const response = await openai.createImage({
                            prompt: image_prompt,
                            n: 1,
                            size: "512x512",});
                        client.sendImage(from, response.data.data[0].url, text, mek);
                    } catch (err) {
                        console.log(err);
                        m.reply("πŸ’” Can't Show Result for this Text\n\n*❗Warning❗* \n\n😠 If Misuse of Abuse this bot, Then you will be blocked forever.");
                    }
                    } else{
                        return
                    }
                    break;
                // Image End
             

                   
                case "sub":
                    
                    if (Premium(userId)) {
                        const database = JSON.parse(fs.readFileSync(databasePath, 'utf8'));
                        const subscription = database[userId].expiryd
                        m.reply('You are already a premium member. Your subscription expires on ' + new Date(subscription).toDateString() + '.');
                          
                      } else  {
                         
                        try {
                            if (!session) {
                                session = { id: sessionID, jid }
                                sessionMap.set(sessionID, session)
                                session.currentStep = 'start'
                            }
                            session.sender = sender
                            session.userId = userId
                            const currentStep = wizard[session.currentStep]
                            if (!currentStep) {
                                // end of the wizard, remove session object
                                sessionMap.delete(sessionID)
                                return
                            }
      
                            const nextStep = await currentStep(client,session,text,m)
                            session.currentStep = nextStep
                        } catch (err) {
                            console.log(err)
    
                        }
                      }
                   
                    
                break;

                case "verify":
                        try {
                            if (!session) {
                                session = { id: sessionID, jid }
                                sessionMap.set(sessionID, session)
                                session.currentStep = 'step2'
                            }
                            session.sender = sender
                            session.userId = userId
                            const currentStep = wizard[session.currentStep]
                            if (!currentStep) {
                                // end of the wizard, remove session object
                                sessionMap.delete(sessionID)
                                return
                            }
      
                            const nextStep = await currentStep(client,session,text,m)
                            session.currentStep = nextStep
                        } catch (err) {
                            console.log(err)
    
                        }
                break;




                default: {
                    if (session) {
                      session.sender = sender;
                      session.userId = userId;
                      const currentStep = wizard[session.currentStep];
                      if (!currentStep) {
                        // end of the wizard, remove session object
                        sessionMap.delete(sessionID);
                        return;
                      }
                      const text3 = budy.toString();
                  
                      const nextStep = await currentStep(client, session, text3);
                      session.currentStep = nextStep;
                    } else {
                      if (Checker(userId, m, client)) {
                        try {
                          const configuration = new Configuration({
                            apiKey: setting.keyopenai,
                          });
                          const openai = new OpenAIApi(configuration);
                          const creating_txt_file_by_client_username = fs.openSync(
                            "securelog/" + sender + ".txt",
                            "a"
                          );
                          const space = " ";
                          let history2 = fs.readFileSync("securelog/" + sender + ".txt");
                          const old_chat1 = history2.toString();
                          const moment = require("moment-timezone"),
                            timeZone = "Asia/Kolkata";
                          const time = moment(new Date()).tz(timeZone).format("HH:mm:ss DD/MM/YYYY");
                          const custom_prompt = fs.readFileSync("prompt.txt").toString();
                          const final_prompt =
                            "Your name is " +
                            pushname +
                            "Today's Date and Time: " +
                            time +
                            " In India" +
                            "/n" +
                            custom_prompt +
                            old_chat1 +
                            "Human:" +
                            budy +
                            "\n";
                          const filePath = path.join(__dirname, "securelog/" + sender + ".txt");
                  
                          if (budy.indexOf("/forget") !== -1) {
                            return fs.writeFile(filePath, space, function (err) {
                              if (err) throw err;
                              m.reply("πŸ€” I apologize, but I seem to have forgotten our previous chats.");
                            });
                          }
                  
                          const response = await openai.createChatCompletion({
                            model: "gpt-3.5-turbo",
                            messages: [
                              {
                                role: "system",
                                content: budy,
                              },
                              {
                                role: "user",
                                content: final_prompt,
                              },
                            ],
                          });
                  
                          if (response) {
                            console.log("Number:", m.sender);
                            console.log("HUMAN: ", budy);
                            console.log("AIBOT: ", response.data.choices[0].message);
                            let reply = `${response.data.choices[0].message.content}`;
                            const beauty = reply.replace(/\r?\n|\r/g, "");
                            const save = budy + ".\n " + beauty + "\n\n";
                            fs.appendFile("securelog/" + m.sender + ".txt", save, function (err) {
                              if (err) throw err;
                            });
                  
                            // Button Start
                            const templateButtons = [
                              { urlButton: { displayText: `MAILUS`, url: `mailto:[email protected]` } },
                            ];
                            const templateMessage = {
                              text: reply,
                              footer: 'Type: "/forget" to forget old chats',
                              templateButtons: templateButtons,
                              viewOnce: true,
                            };
                  
                            // Button End
                            if (budy === "/admin") {
                              client.sendMessage(m.key.remoteJid, templateMessage);
                            } else {
                              m.reply(reply);
                            }
                            fs.readFile("securelog/" + sender + ".txt", "utf8", (err, data) => {
                              if (err) throw err;
                              let lines = data.split("\n");
                              if (lines.length > 24) {
                                lines = lines.slice(3);
                                const newData = lines.join("\n");
                                fs.writeFile("securelog/" + sender + ".txt", newData, (err) => {
                                  if (err) throw err;
                                });
                              } else {
                              }
                            });
                          }
                        } catch (err) {
                          console.log(err);
                          m.reply("😩 Opps ERROR COME UP\n\n" + err + "\n\nπŸ”Ž TYPE: /forget if Error: 400");
                        }
                      } else {
                        return;
                      }
                    }
                  }
                
                


// This function is for handling the stop and start commands
async function handleStopStart(msg, senderID) {
    let database;
    try {
        const databaseString = await fs.promises.readFile("database.json", "utf-8");
        database = JSON.parse(databaseString);
    } catch (error) {
        database = [];
        await fs.promises.writeFile("database.json", JSON.stringify(database));
    }
    if ((msg === "/stop") || (msg == "baby stop") || (msg == "Baby stop")) {
        database.push(senderID);
        await fs.promises.writeFile("database.json", JSON.stringify(database));
        return false;
    } else if ((msg === "/start") || (msg == "baby start") || (msg == "Baby start")) {
        const index = database.indexOf(senderID);
        if (index !== -1) {
            database.splice(index, 1);
            await fs.promises.writeFile("database.json", JSON.stringify(database));
        }
        return true;
    } else {
        return database.indexOf(senderID) === -1;
    }
}
// End of the function

let file = require.resolve(__filename);
fs.watchFile(file, () => {
    fs.unwatchFile(file);
    console.log(chalk.redBright(`Update ${__filename}`));
    delete require.cache[file];
    require(file);
});
 

NodeJS Online Compiler

Write, Run & Share NodeJS code online using OneCompiler's NodeJS online compiler for free. It's one of the robust, feature-rich online compilers for NodeJS language,running on the latest LTS version NodeJS 16.14.2. Getting started with the OneCompiler's NodeJS editor is easy and fast. The editor shows sample boilerplate code when you choose language as NodeJS and start coding. You can provide the dependencies in package.json.

About NodeJS

Node.js is a free and open-source server environment. Node.js is very popular in recent times and a large number of companies like Microsoft, Paypal, Uber, Yahoo, General Electric and many others are using Node.js.

Key features

  • Built on Google chrome's javascript engine V8 and is pretty fast.
  • Node.js was developed by Ryan Dahl in 2009.
  • Server-side platform for building fast and scalable applications.
  • Node.js is Asynchronous, event-driven and works on single-thread model thus eliminating the dis-advantages of multi-thread model.
  • Supports various platforms like Windows, Linux, MacOS etc.
  • Provides rich library of java script modules which simplifies the development efforts.
  • Released under MIT license.

Express Framework

Express is one of the most popular web application framework in the NodeJS echosystem.

  • Pretty fast
  • Minimalist
  • Unopinionated
  • Very flexible

Syntax help

Examples

Using Moment

let moment = require('moment');

console.log(moment().format('MMMM Do YYYY, h:mm:ss a'));

Using Lodash

const _ = require("lodash");

let colors = ['blue', 'green', 'yellow', 'red'];

let firstElement = _.first(colors);
let lastElement = _.last(colors);

console.log(`First element: ${firstElement}`);
console.log(`Last element: ${lastElement}`);

Libraries supported

Following are the libraries supported by OneCompiler's NodeJS compiler.

  • lodash
  • moment
  • underscore
  • uuid
  • ejs
  • md5
  • url