vkashti-bots / daily_tasks.js
daily_tasks.js
Raw
'use strict'
import { Client, GatewayIntentBits } from 'discord.js'
import cron from 'node-cron'
import dotenv from 'dotenv'
import { getNumberEmoji, logger } from './utils.js'
import { createClient } from '@supabase/supabase-js'

dotenv.config()

if (!process.env.SUPABASE_URL || !process.env.SUPABASE_ANON_KEY) {
  throw new Error('Missing Supabase environment variables')
}

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_ANON_KEY
)

const client = new Client({
  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
})

const botToken = process.env.DISCORD_BOT_TOKEN
const channelId = process.env.DISCORD_CHANNEL_ID

// Fetch tasks from Supabase.
async function fetchTasksFromSupabase() {
  console.log('DEBUG: Fetching tasks from Supabase...')
  const { data, error } = await supabase.from('tasks').select('*')
  if (error) {
    console.error('Error fetching tasks from Supabase:', error.message)
    return []
  }
  console.log(`DEBUG: Retrieved ${data.length} tasks from Supabase.`)
  return data
}

// Fetch users with their discord IDs from the database
async function fetchUserProfiles(userIds) {
  if (!userIds || userIds.length === 0) return []
  
  console.log('DEBUG: Fetching user profiles for IDs:', userIds)
  
  // Query using user_id which should match the UUID from schedules
  const { data, error } = await supabase
    .from('profiles')
    .select('id, user_id, discord_id')
    .in('user_id', userIds)
  
  if (error) {
    console.error('Error fetching user profiles:', error.message)
    return []
  }
  
  console.log(`DEBUG: Retrieved ${data.length} user profiles.`)
  console.log('DEBUG: User profiles data:', JSON.stringify(data))
  return data
}

// Modify the fetchCurrentlyWorkingEmployees function to handle timezones correctly.
async function fetchCurrentlyWorkingEmployees() {
  const now = new Date().toISOString()
  console.log(`DEBUG: Fetching schedules for current time: ${now}`)
  const { data, error } = await supabase
    .from('schedules')
    .select('user_id')
    .lte('start_time', now)
    .gte('end_time', now)

  if (error) {
    console.error('Error fetching schedules:', error.message)
    return []
  }

  const userIds = data.map(schedule => schedule.user_id)
  console.log('DEBUG: User IDs from schedules:', userIds)
  return userIds
}

// Determine if a task is due.
function isTaskDue(task, today) {
  const startDate = new Date(task.start_date)
  if (startDate > today) return false
  const daysSinceStart = Math.floor((today - startDate) / (1000 * 60 * 60 * 24))
  return daysSinceStart % task.interval === 0
}

// Modify the sendTasks function
async function sendTasks(tasksToSend, currentTime) {
  console.log(`DEBUG: Preparing to send ${tasksToSend.length} task(s) for ${currentTime}.`)
  console.log(`DEBUG: Attempting to fetch channel with ID: ${channelId}`)
  const channel = await client.channels.fetch(channelId)
  if (!channel) {
    console.error('Channel not found! Channel ID:', channelId)
    return
  }
  console.log('DEBUG: Channel found successfully:', channel.name)

  const workingEmployeeIds = await fetchCurrentlyWorkingEmployees()
  console.log('DEBUG: Currently working employees:', workingEmployeeIds)

  // Fetch user profiles for working employees
  const workingEmployees = await fetchUserProfiles(workingEmployeeIds)
  console.log('DEBUG: Working employees to tag:', workingEmployees)
  
  let messageContent = workingEmployees.length > 0 
    ? `${workingEmployees.filter(emp => emp.discord_id).map(emp => `<@${emp.discord_id}>`).join(' ')}\n\n`
    : '\n\n'

  tasksToSend.forEach((task, idx) => {
    messageContent += `${getNumberEmoji(idx + 1)} ${task.name}\n`
  })
  
  console.log('DEBUG: Message content:', messageContent)

  try {
    const sentMessage = await channel.send(messageContent)
    console.log('DEBUG: Message sent. Now adding reactions...')
    for (let i = 1; i <= tasksToSend.length; i++) {
      const emoji = getNumberEmoji(i)
      if (emoji) {
        await sentMessage.react(emoji)
        console.log(`DEBUG: Added reaction ${emoji}`)
      }
    }
    logger(`Tasks sent for ${currentTime}.`)
  } catch (err) {
    console.error('DEBUG: Error sending tasks:', err)
  }
}

// Cron job: runs every minute in Sofia time.
cron.schedule(
  '* * * * *',
  async () => {
    const now = new Date()
    const currentTime = now.toLocaleTimeString('en-GB', {
      timeZone: 'Europe/Sofia',
      hour12: false,
      hour: '2-digit',
      minute: '2-digit',
    })
    console.log(`DEBUG: Cron job triggered at ${currentTime} (Sofia time).`)

    const allTasks = await fetchTasksFromSupabase()
    const today = new Date()

    // Filter tasks that are due and scheduled for the current time.
    const dueTasks = allTasks.filter((task) => {
      return isTaskDue(task, today) && task.time === currentTime
    })

    if (dueTasks.length > 0) {
      console.log(
        `DEBUG: Found ${dueTasks.length} due task(s) for ${currentTime}.`
      )
      await sendTasks(dueTasks, currentTime)
    } else {
      console.log(`DEBUG: No tasks due for ${currentTime}. Enjoy the silence.`)
    }
  },
  { timezone: 'Europe/Sofia' }
)

client.once('ready', () => {
  logger('Bot is ready.')
  console.log('DEBUG: Discord client is now ready.')
})

client.login(botToken)