!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/home/picotech/domains/note.picotech.app/public_html/src/controllers/   drwxr-xr-x
Free 25.93 GB of 117.98 GB (21.98%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     meetingController.js (14.24 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
const { Meeting, Note, Recording, Transcript, Summary, User } = require('../models');
const { AppError, catchAsync } = require('../middleware/errorHandler');
const { Op } = require('sequelize');

// Create new meeting (auto-triggered for live note sessions)
const createMeeting = catchAsync(async (req, res) => {
  const {
    title,
    description,
    start_time,
    end_time,
    attendees,
    location,
    meeting_url,
    tags,
    labels,
    calendar_source = 'manual',
    external_id,
  } = req.body;

  const userId = req.user.id;

  // Auto-generate title if not provided (for live note sessions)
  const meetingTitle = title || `Live Note Session - ${new Date().toLocaleDateString()}`;

  const meeting = await Meeting.create({
    title: meetingTitle,
    description,
    start_time: start_time || new Date(),
    end_time,
    user_id: userId,
    attendees: attendees || [],
    location,
    meeting_url,
    tags: tags || [],
    labels: labels || [],
    calendar_source,
    external_id,
    status: 'active',
  });

  // Include user information in response
  const meetingWithUser = await Meeting.findByPk(meeting.id, {
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'name', 'email'],
      },
    ],
  });

  // Update the Redux state with the new meeting
  // This will be handled by the React Native app when it starts a live note session
  res.status(201).json({
    success: true,
    message: 'Meeting created successfully',
    data: { meeting: meetingWithUser },
  });
});

// Auto-create meeting when a user starts a live note session
const startLiveNoteSession = catchAsync(async (req, res) => {
  const userId = req.user.id;

  // Auto-generate title for live note session
  const meetingTitle = `Live Note Session - ${new Date().toLocaleDateString()}`;

  const meeting = await Meeting.create({
    title: meetingTitle,
    description: 'Live note session started',
    start_time: new Date(),
    end_time: null,
    user_id: userId,
    attendees: [],
    location: null,
    meeting_url: null,
    tags: [],
    calendar_source: 'manual',
    external_id: null,
    status: 'active',
  });

  res.status(201).json({
    success: true,
    message: 'Live note session started successfully',
    data: { meeting },
  });
});

// Get all meetings for the authenticated user
const getMeetings = catchAsync(async (req, res) => {
  const userId = req.user.id;
  const {
    page = 1,
    limit = 20,
    status,
    start_date,
    end_date,
    search,
    sort_by = 'start_time',
    sort_order = 'DESC',
  } = req.query;

  const offset = (page - 1) * limit;
  const whereClause = { user_id: userId };

  // Add filters
  if (status) {
    whereClause.status = status;
  }

  if (start_date && end_date) {
    whereClause.start_time = {
      [Op.between]: [new Date(start_date), new Date(end_date)],
    };
  } else if (start_date) {
    whereClause.start_time = {
      [Op.gte]: new Date(start_date),
    };
  } else if (end_date) {
    whereClause.start_time = {
      [Op.lte]: new Date(end_date),
    };
  }

  if (search) {
    whereClause[Op.or] = [
      { title: { [Op.like]: `%${search}%` } },
      { description: { [Op.like]: `%${search}%` } },
    ];
  }

  const { count, rows: meetings } = await Meeting.findAndCountAll({
    where: whereClause,
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'name', 'email'],
      },
      {
        model: Note,
        as: 'notes',
        attributes: ['id', 'title', 'status', 'created_at'],
      },
      {
        model: Recording,
        as: 'recordings',
        attributes: ['id', 'file_name', 'duration', 'status'],
      },
      {
        model: Summary,
        as: 'summary',
        attributes: ['id', 'overview', 'status', 'created_at'],
      },
    ],
    order: [[sort_by, sort_order.toUpperCase()]],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  const totalPages = Math.ceil(count / limit);

  res.json({
    success: true,
    data: {
      meetings,
      pagination: {
        current_page: parseInt(page),
        total_pages: totalPages,
        total_items: count,
        items_per_page: parseInt(limit),
        has_next: page < totalPages,
        has_prev: page > 1,
      },
    },
  });
});

// Get single meeting by ID
const getMeeting = catchAsync(async (req, res) => {
  const { id } = req.params;
  const userId = req.user.id;

  const meeting = await Meeting.findOne({
    where: { id, user_id: userId },
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'name', 'email'],
      },
      {
        model: Note,
        as: 'notes',
        include: [
          {
            model: User,
            as: 'user',
            attributes: ['id', 'name'],
          },
        ],
        order: [['created_at', 'ASC']],
      },
      {
        model: Recording,
        as: 'recordings',
        include: [
          {
            model: Transcript,
            as: 'transcript',
            attributes: ['id', 'content', 'confidence', 'status'],
          },
        ],
        order: [['timestamp', 'ASC']],
      },
      {
        model: Summary,
        as: 'summary',
      },
    ],
  });

  if (!meeting) {
    throw new AppError('Meeting not found', 404, 'MEETING_NOT_FOUND');
  }

  res.json({
    success: true,
    data: { meeting },
  });
});

// Update meeting
const updateMeeting = catchAsync(async (req, res) => {
  const { id } = req.params;
  const userId = req.user.id;
  const {
    title,
    description,
    start_time,
    end_time,
    status,
    attendees,
    location,
    meeting_url,
    tags,
    labels,
  } = req.body;

  const meeting = await Meeting.findOne({
    where: { id, user_id: userId },
  });

  if (!meeting) {
    throw new AppError('Meeting not found', 404, 'MEETING_NOT_FOUND');
  }

  // Update fields
  if (title !== undefined) meeting.title = title;
  if (description !== undefined) meeting.description = description;
  if (start_time !== undefined) meeting.start_time = new Date(start_time);
  if (end_time !== undefined) meeting.end_time = end_time ? new Date(end_time) : null;
  if (status !== undefined) meeting.status = status;
  if (attendees !== undefined) meeting.attendees = attendees;
  if (location !== undefined) meeting.location = location;
  if (meeting_url !== undefined) meeting.meeting_url = meeting_url;
  if (tags !== undefined) meeting.tags = tags;
  if (labels !== undefined) meeting.labels = labels;

  // Auto-set end_time when completing meeting
  if (status === 'completed' && !meeting.end_time) {
    meeting.end_time = new Date();
  }

  await meeting.save();

  // Fetch updated meeting with associations
  const updatedMeeting = await Meeting.findByPk(meeting.id, {
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'name', 'email'],
      },
    ],
  });

  res.json({
    success: true,
    message: 'Meeting updated successfully',
    data: { meeting: updatedMeeting },
  });
});

// Delete meeting
const deleteMeeting = catchAsync(async (req, res) => {
  const { id } = req.params;
  const userId = req.user.id;

  const meeting = await Meeting.findOne({
    where: { id, user_id: userId },
  });

  if (!meeting) {
    throw new AppError('Meeting not found', 404, 'MEETING_NOT_FOUND');
  }

  await meeting.destroy();

  res.json({
    success: true,
    message: 'Meeting deleted successfully',
  });
});

// Complete meeting (end live session)
const completeMeeting = catchAsync(async (req, res) => {
  const { id } = req.params;
  const userId = req.user.id;

  const meeting = await Meeting.findOne({
    where: { id, user_id: userId },
  });

  if (!meeting) {
    throw new AppError('Meeting not found', 404, 'MEETING_NOT_FOUND');
  }

  if (meeting.status === 'completed') {
    throw new AppError('Meeting is already completed', 400, 'MEETING_ALREADY_COMPLETED');
  }

  await meeting.complete();

  res.json({
    success: true,
    message: 'Meeting completed successfully',
    data: { meeting },
  });
});

// Get active meetings for user
const getActiveMeetings = catchAsync(async (req, res) => {
  const userId = req.user.id;

  const meetings = await Meeting.findActiveByUser(userId);

  res.json({
    success: true,
    data: { meetings },
  });
});

// Get meeting statistics
const getMeetingStats = catchAsync(async (req, res) => {
  const userId = req.user.id;
  const { start_date, end_date } = req.query;

  const whereClause = { user_id: userId };

  if (start_date && end_date) {
    whereClause.start_time = {
      [Op.between]: [new Date(start_date), new Date(end_date)],
    };
  }

  const [
    totalMeetings,
    activeMeetings,
    completedMeetings,
    totalNotes,
    totalRecordings,
    totalSummaries,
  ] = await Promise.all([
    Meeting.count({ where: whereClause }),
    Meeting.count({ where: { ...whereClause, status: 'active' } }),
    Meeting.count({ where: { ...whereClause, status: 'completed' } }),
    Note.count({
      include: [{ model: Meeting, where: whereClause, attributes: [] }],
    }),
    Recording.count({
      include: [{ model: Meeting, where: whereClause, attributes: [] }],
    }),
    Summary.count({
      include: [{ model: Meeting, where: whereClause, attributes: [] }],
    }),
  ]);

  // Calculate average meeting duration for completed meetings
  const completedMeetingsWithDuration = await Meeting.findAll({
    where: {
      ...whereClause,
      status: 'completed',
      end_time: { [Op.not]: null },
    },
    attributes: ['start_time', 'end_time'],
  });

  let averageDuration = 0;
  if (completedMeetingsWithDuration.length > 0) {
    const totalDuration = completedMeetingsWithDuration.reduce((sum, meeting) => {
      const duration = new Date(meeting.end_time) - new Date(meeting.start_time);
      return sum + duration;
    }, 0);
    averageDuration = Math.floor(totalDuration / completedMeetingsWithDuration.length / (1000 * 60)); // in minutes
  }

  res.json({
    success: true,
    data: {
      stats: {
        total_meetings: totalMeetings,
        active_meetings: activeMeetings,
        completed_meetings: completedMeetings,
        total_notes: totalNotes,
        total_recordings: totalRecordings,
        total_summaries: totalSummaries,
        average_duration_minutes: averageDuration,
      },
    },
  });
});

// Search meetings
const searchMeetings = catchAsync(async (req, res) => {
  const userId = req.user.id;
  const { q: query, page = 1, limit = 20 } = req.query;

  if (!query) {
    throw new AppError('Search query is required', 400, 'MISSING_SEARCH_QUERY');
  }

  const offset = (page - 1) * limit;

  const { count, rows: meetings } = await Meeting.findAndCountAll({
    where: {
      user_id: userId,
      [Op.or]: [
        { title: { [Op.like]: `%${query}%` } },
        { description: { [Op.like]: `%${query}%` } },
      ],
    },
    include: [
      {
        model: User,
        as: 'user',
        attributes: ['id', 'name', 'email'],
      },
    ],
    order: [['start_time', 'DESC']],
    limit: parseInt(limit),
    offset: parseInt(offset),
  });

  const totalPages = Math.ceil(count / limit);

  res.json({
    success: true,
    data: {
      meetings,
      pagination: {
        current_page: parseInt(page),
        total_pages: totalPages,
        total_items: count,
        items_per_page: parseInt(limit),
      },
    },
  });
});
// Sync calendar meetings
const syncCalendarMeetings = catchAsync(async (req, res) => {
  const userId = req.user.id;
  const { calendarEvents } = req.body;

  if (!Array.isArray(calendarEvents)) {
    throw new AppError('Calendar events must be an array', 400, 'INVALID_CALENDAR_EVENTS');
  }

  const syncedMeetings = [];
  const skippedMeetings = [];

  for (const event of calendarEvents) {
    try {
      // Check if meeting already exists with this external_id
      const existingMeeting = await Meeting.findOne({
        where: {
          user_id: userId,
          external_id: event.id,
          calendar_source: event.calendarSource || 'google',
        },
      });

      if (existingMeeting) {
        // Skip existing meeting - do not update
        skippedMeetings.push({
          eventId: event.id,
          title: event.title,
          reason: 'Already synced',
        });
      } else {
        // Create new meeting from calendar event
        const newMeeting = await Meeting.create({
          title: event.title,
          description: event.description || '',
          start_time: new Date(event.startDate),
          end_time: event.endDate ? new Date(event.endDate) : null,
          user_id: userId,
          attendees: event.attendees || [],
          location: event.location || null,
          meeting_url: event.meetingUrl || null,
          tags: event.tags || [],
          labels: event.labels || [],
          calendar_source: event.calendarSource || 'google',
          external_id: event.id,
          status: 'active',
        });
        syncedMeetings.push(newMeeting);
      }
    } catch (error) {
      console.error('Error syncing calendar event:', event.id, error);
      skippedMeetings.push({
        eventId: event.id,
        title: event.title,
        error: error.message,
      });
    }
  }

  res.json({
    success: true,
    message: `Synced ${syncedMeetings.length} calendar meetings`,
    data: {
      synced_count: syncedMeetings.length,
      skipped_count: skippedMeetings.length,
      synced_meetings: syncedMeetings,
      skipped_meetings: skippedMeetings,
    },
  });
});

// Get calendar meetings for sync
const getCalendarMeetings = catchAsync(async (req, res) => {
  const userId = req.user.id;
  const { calendar_source, start_date, end_date } = req.query;

  const whereClause = {
    user_id: userId,
    calendar_source: { [Op.ne]: 'manual' }, // Only calendar-sourced meetings
  };

  if (calendar_source) {
    whereClause.calendar_source = calendar_source;
  }

  if (start_date && end_date) {
    whereClause.start_time = {
      [Op.between]: [new Date(start_date), new Date(end_date)],
    };
  }

  const meetings = await Meeting.findAll({
    where: whereClause,
    order: [['start_time', 'ASC']],
  });

  res.json({
    success: true,
    data: { meetings },
  });
});

module.exports = {
  createMeeting,
  getMeetings,
  getMeeting,
  updateMeeting,
  deleteMeeting,
  completeMeeting,
  getActiveMeetings,
  getMeetingStats,
  searchMeetings,
  syncCalendarMeetings,
  getCalendarMeetings,
};

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0047 ]--