HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/good-life-be/helper/questionsCron.js
import moment from 'moment';
import { spawn } from 'child_process';
import { dirname, join } from 'path';
import Event from '../models/Event.js';

import __dirname from '../path.js';
import User from '../models/User.js';
import EventCounts from '../models/eventsCount.js';

import { preprocessEvents } from './eventsUtils.js';
import BadRequest from './exception/badRequest.js';
import FormData from '../models/formDataModel.js';
import sendEmails from './sendEmail.js';
import Login from '../models/Login.js';

// Function to get the last inserted date for a user

async function isUserActive(userId) {
  const user = await User.findOne({
    where: { id: userId },
    attributes: ['eventStatus'],
  });

  return user?.eventStatus === 'pending'; // Return true if active, false otherwise
}
async function getLastProcessedDate(userId) {
  const lastEvent = await Event.findOne({
    where: { user_id: userId, status: 'active' },
    order: [['date', 'DESC']],
    attributes: ['date'],
    raw: true,
  });

  return lastEvent ? lastEvent?.date : null;
}

async function updateUserEventStatus(userId, status) {
  await User.update({ eventStatus: status }, { where: { id: userId } });
}

async function sendDataToPython(data, events, test) {
  return new Promise((resolve, reject) => {
    const pythonScriptPath = join(
      __dirname,
      'helper/gpt_schedule_optimizer.py'
    ); // Ensure correct path

    let argsArray = [pythonScriptPath, data, events, test];

    // Convert the data to JSON string
    // const jsonData = JSON.stringify({ date, events });

    // Spawn the Python process
    const pythonExecutable = 'python3';

    const pythonProcess = spawn(pythonExecutable, argsArray); // Use 'python3' if needed

    let stdoutData = '';
    let stderrData = '';

    // // Send JSON data to Python via stdin
    // pythonProcess.stdin.write(jsonData);
    // pythonProcess.stdin.end();

    // Capture stdout data
    pythonProcess.stdout.on('data', (data) => {
      stdoutData += data;
    });

    // Capture stderr data
    pythonProcess.stderr.on('data', (data) => {
      stderrData += data;
    });

    // Handle process close
    pythonProcess.on('close', (code) => {
      if (code === 0) {
        resolve(stdoutData.trim());
      } else {
        reject(
          new Error(`Python script exited with code ${code}: ${stderrData}`)
        );
      }
    });

    // Handle process errors
    pythonProcess.on('error', (err) => {
      reject(new Error(`Failed to start Python script: ${err.message}`));
    });
  });
}

const checkAndUpdateUserStatus = async (userId) => {
  try {
    // Get the last date from the Event table for the user
    const lastEvent = await Event.findOne({
      where: { user_id: userId },
      order: [['date', 'DESC']], // Get the latest event
      attributes: ['date'], // Only fetch the date field
      raw: true,
    });

    if (!lastEvent || !lastEvent.date) {
      console.log(`No events found for user ${userId}`);
      return;
    }

    const lastEventDate = lastEvent.date;
    console.log(`Last event date for user ${userId}:`, lastEventDate);

    // Check if this last date exists in the database
    const existingEvent = await Event.findOne({
      where: { user_id: userId, date: lastEventDate },
      raw: true,
    });

    if (!existingEvent) {
      console.log(
        `Last event date ${lastEventDate} is missing for user ${userId}. Updating status to processing...`
      );

      // Update FormData status to 'processing' for this user
      await FormData.update(
        { status: 'processing' },
        { where: { user_id: userId } }
      );
    } else {
      console.log(
        `All events entered correctly for user ${userId}. No update needed.`
      );
    }
  } catch (error) {
    console.error('Error checking and updating user status:', error.message);
  }
};
// Function to execute the cron job
export const runCronJob = async (response, user) => {
  try {
    // let dayData;
    const userId = user; // Replace with dynamic user ID

    // Check if user eventStatus is active
    const isActive = await isUserActive(userId);

    if (!isActive) {
      console.log(`User ${userId} eventStatus is inactive. Skipping cron job.`);
      throw new BadRequest('User Already has events');
      return;
    }

    console.log('Starting cron job...');

    if (!response.Data?.Calendar) {
      return;
    }

    const dayData = Object.entries(response.Data.Calendar).map(
      ([date, { events }]) => ({
        date,
        events,
        priorityLevel: response.Data.Priority_Level,
        distributionData: response.Data.distribution_data,
      })
    );

    // console.log('dayData', dayData);

    const lastProcessedDate = await getLastProcessedDate(userId);

    console.log('lastProcessedDate', lastProcessedDate);
    // const today = moment().startOf('day');
    // const startDate = lastProcessedDate ? lastProcessedDate : today;

    const lastProcessedMoment = moment(lastProcessedDate); // Convert once

    const filteredDates = Object.entries(response.Data.Calendar)
      .filter(([date]) =>
        lastProcessedDate ? moment(date).isAfter(lastProcessedMoment) : true
      ) // Only future dates
      .sort(([dateA], [dateB]) => moment(dateA).diff(moment(dateB))); // Sort by date in ascending order

    if (filteredDates.length === 0) {
      console.log('No new events to process.');
      return;
    }

    let totalProcessedDays = 0;

    await FormData.update(
      { status: 'processing' },
      { where: { user_id: userId } }
    );

    // Process up to 365 days
    // const datesToProcess = dayEvents.slice(0, 365);

    for (const [date, details] of filteredDates) {
      const dayDataPython = {
        [date]: details,
      };

      await FormData.update({ dataStatus: 0 }, { where: { user_id: user } });

      const [lastDate] = filteredDates.slice(-1); // Gets the last element using slice
      const currentDate = date; // Current processing date

      // const { startTime, endTime, eventTitle } = details; // Extract required values

      // const uniqueKey = `${date}_${startTime}-${endTime}_${eventTitle.replace(/\s+/g, '')}`;

      // console.log('Generated Unique Key:', uniqueKey);

      const diffInDays = Math.floor(
        (new Date(lastDate[0]) - new Date(currentDate)) / (1000 * 60 * 60 * 24)
      );
      console.log('Last Date:', lastDate[0]);

      const remainingDays = 365 - diffInDays;

      console.log('Remaining Days:', remainingDays);
      console.log('Processing date:', date); // ✅ This will print each date
      //   console.log('filteredDates', filteredDates);
      let priority_levels = response.Data.Priority_Level;
      let distribution_data = response.Data.distribution_data;
      const formData = await FormData.findOne({ where: { user_id: user } });

      // ✅ Only proceed if dataStatus is 1 (previous event was inserted successfully)
      // if (formData?.dataStatus === 1) {
      //   console.log(
      //     `Skipping API call for ${date}, waiting for previous event insertion.`
      //   );
      //   continue; // Skip API call until the previous event is inserted
      // }

      // await FormData.update({ dataStatus: 1 }, { where: { user_id: user } });

      let result;
      try {
        result = await sendDataToPython(
          JSON.stringify(dayDataPython),
          JSON.stringify(priority_levels),
          JSON.stringify(distribution_data)
        ); // Await the result
        // ✅ Find first '{' to extract only JSON part
        // Find the start of the JSON object
        if (typeof result === 'string') {
          // Remove any surrounding quotes if they exist
          result = result.replace(/^"|"$/g, '');
        }

        // **Check if result contains "fail" and skip iteration**
        if (result.toLowerCase().includes('fali')) {
          console.log(`Skipping processing for date: ${date} due to failure.`);
          continue; // Skip current iteration and move to the next date
        }
        let parsedResult;
        try {
          parsedResult = JSON.parse(result);
        } catch (error) {
          console.log('error In parsing', error);
          throw new BadRequest(error);
        }

        // ✅ Extract only the Calendar object
        let extractedCalendar =
          parsedResult?.Calendar?.Calendar || parsedResult?.Calendar;
        const eventData = await preprocessEvents(extractedCalendar, user);
        for (const event of eventData) {
          const createdEvent = await Event.create(event); // Insert event into DB

          // if (createdEvent) {
          //   // Update dataStatus to 1 after successful event insertion
          //   // await FormData.update(
          //   //   { dataStatus: 0 },
          //   //   { where: { user_id: user } }
          //   // );
          // }
        }
        const existingCount = await EventCounts.findOne({
          where: { user_id: user },
        });

        if (!existingCount) {
          // If no entry exists, create a new one
          await EventCounts.create({
            user_id: user,
            count: remainingDays,
          });
        } else {
          // If entry exists, update the count

          await EventCounts.update(
            { count: remainingDays },
            { where: { user_id: user } }
          );
        }
      } catch (error) {
        console.log('error', error);
        throw new BadRequest(error.message);
      }

      await FormData.update({ dataStatus: 0 }, { where: { user_id: user } });
    }

    console.log(
      `Cron job execution completed. Total events processed: ${totalProcessedDays}`
    );

    // After processing all 365 days, update eventStatus to inactive
    await EventCounts.update(
      { count: 0, eventStatus: 'active' },
      { where: { user_id: user } }
    );
    await updateUserEventStatus(userId, 'active');
    await FormData.update(
      { status: 'completed' },
      { where: { user_id: user } }
    );
    console.log(`User ${userId} eventStatus updated to inactive.`);
    const { MAILER_NAME, MAILER_AUTH_USER, WEB_DOMAIN } = process.env;

    const users = await User.findOne({
      where: {
        id: user,
      },
      raw: true,
    });

    const login = await Login.findOne({
      where: { user_id: user },
      attributes: ['email'],
      raw: true,
    });

    const mailOptions = {
      from: 'midhun@spericorn.com',
      to: login.email,
      subject: 'Your Calendar Optimization is Complete! 🎉',
    };
    const contentVarialbles = {
      name: `${users.first_name} ${users.second_name}`,
      feUrl: 'https://calendar-dev.spericorn.com/calendar',
    };

    const fileName = 'calenderGenerated.ejs';

    sendEmails({ mailOptions, fileName, contentVarialbles });
    return 'Completed';
  } catch (error) {
    console.log('error Final', error);
    throw new BadRequest(error.message);
  }
};

console.log('Cron job scheduled to run daily at midnight.');