// ============================================================================ // Miku Control Panel — DM Management Module // ============================================================================ async function loadDMUsers() { try { const result = await apiCall('/dms/users'); displayDMUsers(result.users); } catch (error) { console.error('Failed to load DM users:', error); } } function displayDMUsers(users) { const container = document.getElementById('dm-users-list'); if (!users || users.length === 0) { container.innerHTML = '

No DM conversations found.

'; return; } let html = '
'; users.forEach(user => { console.log(`šŸ‘¤ Processing user: ${user.username} (ID: ${user.user_id})`); const lastMessage = user.last_message ? `Last: ${user.last_message.content}` : 'No messages yet'; const lastTime = user.last_message ? new Date(user.last_message.timestamp).toLocaleString() : 'Never'; html += `

šŸ‘¤ ${user.username}

ID: ${user.user_id}

Total Messages: ${user.total_messages}

User Messages: ${user.user_messages}

Bot Messages: ${user.bot_messages}

Last Activity: ${lastTime}

Last Message: ${lastMessage}

`; }); html += '
'; container.innerHTML = html; // Add event listeners after HTML is inserted addDMUserEventListeners(); } function addDMUserEventListeners() { // Add event listeners for view chat buttons document.querySelectorAll('.view-chat-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); console.log(`šŸŽÆ View chat clicked for user ID: ${userId} (type: ${typeof userId})`); viewUserConversations(userId); }); }); // Add event listeners for export buttons document.querySelectorAll('.export-dms-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); console.log(`šŸŽÆ Export clicked for user ID: ${userId} (type: ${typeof userId})`); exportUserDMs(userId); }); }); // Add event listeners for analyze buttons document.querySelectorAll('.analyze-user-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); const username = this.getAttribute('data-username'); console.log(`šŸŽÆ Analyze clicked for user ID: ${userId} (type: ${typeof userId})`); analyzeUserInteraction(userId, username); }); }); // Add event listeners for block buttons document.querySelectorAll('.block-user-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); const username = this.getAttribute('data-username'); console.log(`šŸŽÆ Block clicked for user ID: ${userId} (type: ${typeof userId})`); blockUser(userId, username); }); }); // Add event listeners for delete all DMs buttons document.querySelectorAll('.delete-all-dms-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); const username = this.getAttribute('data-username'); console.log(`šŸŽÆ Delete all DMs clicked for user ID: ${userId} (type: ${typeof userId})`); deleteAllUserConversations(userId, username); }); }); // Add event listeners for delete user completely buttons document.querySelectorAll('.delete-user-completely-btn').forEach(button => { button.addEventListener('click', function() { const userId = this.getAttribute('data-user-id'); const username = this.getAttribute('data-username'); console.log(`šŸŽÆ Delete user completely clicked for user ID: ${userId} (type: ${typeof userId})`); deleteUserCompletely(userId, username); }); }); } async function viewUserConversations(userId) { try { // Ensure userId is always treated as a string const userIdStr = String(userId); console.log(`šŸ” Loading conversations for user ${userIdStr} (type: ${typeof userIdStr})`); console.log(`šŸ” Original userId: ${userId} (type: ${typeof userId})`); console.log(`šŸ” userIdStr: ${userIdStr} (type: ${typeof userIdStr})`); const result = await apiCall(`/dms/users/${userIdStr}/conversations?limit=100`); console.log('šŸ“” API Response:', result); console.log('šŸ“” API URL called:', `/dms/users/${userIdStr}/conversations?limit=100`); if (result.conversations && result.conversations.length > 0) { console.log(`āœ… Found ${result.conversations.length} conversations`); displayUserConversations(userIdStr, result.conversations); } else { console.log('āš ļø No conversations found in response'); showNotification('No conversations found for this user', 'info'); // Go back to user list loadDMUsers(); } } catch (error) { console.error('Failed to load user conversations:', error); } } function displayUserConversations(userId, conversations) { console.log(`šŸŽØ Displaying conversations for user ${userId}:`, conversations); // Create a modal or expand the user card to show conversations const container = document.getElementById('dm-users-list'); let html = `

šŸ’¬ Conversations with User ${userId}

`; if (!conversations || conversations.length === 0) { html += '

No conversations found for this user.

'; } else { conversations.forEach((msg, index) => { console.log(`šŸ“ Processing message ${index}:`, msg); const timestamp = new Date(msg.timestamp).toLocaleString(); const sender = msg.is_bot_message ? 'šŸ¤– Miku' : 'šŸ‘¤ User'; const content = msg.content || '[No text content]'; const messageId = msg.message_id || msg.timestamp; // Use message_id or timestamp as identifier const escapedContent = content.replace(/'/g, "\\'").replace(/"/g, '\\"'); // Debug: Log message details console.log(`šŸ“ Message ${index}: id=${messageId}, is_bot=${msg.is_bot_message}, content="${content.substring(0, 30)}..."`); // Only show delete button for bot messages (Miku can only delete her own messages) const deleteButton = msg.is_bot_message ? `` : ''; html += `
${sender} ${timestamp} ${deleteButton}
${content}
${msg.attachments && msg.attachments.length > 0 ? `
šŸ“Ž Attachments: ${msg.attachments.map(att => `
- ${att.filename} (${att.size} bytes) šŸ”— View
`).join('')}
` : ''} ${msg.reactions && msg.reactions.length > 0 ? `
${msg.reactions.map(reaction => { const reactionTime = new Date(reaction.added_at).toLocaleString(); const reactorType = reaction.is_bot ? 'bot-reaction' : 'user-reaction'; const reactorLabel = reaction.is_bot ? 'šŸ¤– Miku' : `šŸ‘¤ ${reaction.reactor_name}`; return `
${reaction.emoji} ${reactorLabel}
`; }).join('')}
` : ''}
`; }); } html += `
`; console.log('šŸŽØ Generated HTML:', html); container.innerHTML = html; } async function exportUserDMs(userId) { try { // Ensure userId is always treated as a string const userIdStr = String(userId); await apiCall(`/dms/users/${userIdStr}/export?format=txt`); showNotification(`DM export completed for user ${userIdStr}`); // You could trigger a download here if the file is accessible } catch (error) { console.error('Failed to export user DMs:', error); } } async function deleteUserDMs(userId) { // Ensure userId is always treated as a string const userIdStr = String(userId); if (!confirm(`Are you sure you want to delete all DM logs for user ${userIdStr}? This action cannot be undone.`)) { return; } try { await apiCall(`/dms/users/${userIdStr}`, 'DELETE'); showNotification(`Deleted DM logs for user ${userIdStr}`); loadDMUsers(); // Refresh the list } catch (error) { console.error('Failed to delete user DMs:', error); } } // ========== User Blocking & Advanced Deletion Functions ========== async function blockUser(userId, username) { const userIdStr = String(userId); if (!confirm(`Are you sure you want to block ${username} (${userIdStr}) from sending DMs to Miku?`)) { return; } try { await apiCall(`/dms/users/${userIdStr}/block`, 'POST'); showNotification(`${username} has been blocked from sending DMs`); loadDMUsers(); // Refresh the list } catch (error) { console.error('Failed to block user:', error); } } async function unblockUser(userId, username) { const userIdStr = String(userId); try { await apiCall(`/dms/users/${userIdStr}/unblock`, 'POST'); showNotification(`${username} has been unblocked`); loadBlockedUsers(); // Refresh blocked users list } catch (error) { console.error('Failed to unblock user:', error); } } async function deleteAllUserConversations(userId, username) { const userIdStr = String(userId); if (!confirm(`āš ļø DELETE ALL CONVERSATIONS with ${username} (${userIdStr})?\n\nThis will:\n• Delete ALL Miku messages from Discord DM\n• Clear all conversation logs\n• Keep the user record\n\nThis action CANNOT be undone!\n\nClick OK to confirm deletion.`)) { return; } try { await apiCall(`/dms/users/${userIdStr}/conversations/delete-all`, 'POST'); showNotification(`Bulk deletion queued for ${username} (deleting all Miku messages from Discord and logs)`); setTimeout(() => { loadDMUsers(); // Refresh after a delay to allow deletion to process }, 2000); } catch (error) { console.error('Failed to delete conversations:', error); } } async function deleteUserCompletely(userId, username) { const userIdStr = String(userId); if (!confirm(`🚨 COMPLETELY DELETE USER ${username} (${userIdStr})?\n\nThis will:\n• Delete ALL conversation history\n• Delete the entire user log file\n• Remove ALL traces of this user\n\nThis action is PERMANENT and CANNOT be undone!\n\nType "${username}" below to confirm:`)) { return; } const confirmName = prompt(`Type the username "${username}" to confirm complete deletion:`); if (confirmName !== username) { showNotification('Deletion cancelled - username did not match', 'error'); return; } try { await apiCall(`/dms/users/${userIdStr}/delete-completely`, 'POST'); showNotification(`${username} has been completely deleted from the system`); loadDMUsers(); // Refresh the list } catch (error) { console.error('Failed to delete user completely:', error); } } async function deleteConversation(userId, conversationId, messageContent) { const userIdStr = String(userId); if (!confirm(`Delete this Miku message from Discord and logs?\n\n"${messageContent.substring(0, 100)}${messageContent.length > 100 ? '...' : ''}"\n\nThis will:\n• Delete the message from Discord DM\n• Remove it from conversation logs\n\nNote: Only Miku's messages can be deleted.\nThis action cannot be undone.`)) { return; } try { await apiCall(`/dms/users/${userIdStr}/conversations/${conversationId}/delete`, 'POST'); showNotification('Miku message deletion queued (deleting from both Discord and logs)'); setTimeout(() => { viewUserConversations(userId); // Refresh after a short delay to allow deletion to process }, 1000); } catch (error) { console.error('Failed to delete conversation:', error); } } async function analyzeUserInteraction(userId, username) { const userIdStr = String(userId); if (!confirm(`Run DM interaction analysis for ${username}?\n\nThis will:\n• Analyze their messages from the last 24 hours\n• Generate a sentiment report\n• Send report to bot owner\n\nMinimum 3 messages required for analysis.`)) { return; } try { showNotification(`Analyzing ${username}'s interactions...`, 'info'); const result = await apiCall(`/dms/users/${userIdStr}/analyze`, 'POST'); if (result.reported) { showNotification(`āœ… Analysis complete! Report sent to bot owner for ${username}`); } else { showNotification(`šŸ“Š Analysis complete for ${username} (not enough messages or already reported today)`); } } catch (error) { console.error('Failed to analyze user:', error); } } async function runDailyAnalysis() { if (!confirm('Run the daily DM interaction analysis now?\n\nThis will:\n• Analyze all DM users from the last 24 hours\n• Report one significant interaction to the bot owner\n• Skip users already reported today\n\nNote: This runs automatically at 2 AM daily.')) { return; } try { showNotification('Starting DM interaction analysis...', 'info'); await apiCall('/dms/analysis/run', 'POST'); showNotification('āœ… DM analysis completed! Check bot owner\'s DMs for any reports.'); } catch (error) { console.error('Failed to run DM analysis:', error); } } async function viewAnalysisReports() { try { showNotification('Loading analysis reports...', 'info'); const result = await apiCall('/dms/analysis/reports?limit=50'); displayAnalysisReports(result.reports); } catch (error) { console.error('Failed to load reports:', error); } } function displayAnalysisReports(reports) { const container = document.getElementById('dm-users-list'); if (!reports || reports.length === 0) { container.innerHTML = `

No analysis reports found yet.

`; return; } let html = `
${reports.length} reports found
`; reports.forEach(report => { const sentimentColor = report.sentiment_score >= 5 ? '#4caf50' : report.sentiment_score <= -3 ? '#f44336' : '#2196f3'; const sentimentEmoji = report.sentiment_score >= 5 ? '😊' : report.sentiment_score <= -3 ? '😢' : '😐'; const timestamp = new Date(report.analyzed_at).toLocaleString(); html += `

${sentimentEmoji} ${report.username}

User ID: ${report.user_id}

${report.sentiment_score > 0 ? '+' : ''}${report.sentiment_score}/10
${report.overall_sentiment}
Miku's Feelings:

"${report.your_feelings}"

${report.notable_moment ? `
Notable Moment:

"${report.notable_moment}"

` : ''} ${report.key_behaviors && report.key_behaviors.length > 0 ? `
Key Behaviors:
    ${report.key_behaviors.slice(0, 5).map(b => `
  • ${b}
  • `).join('')}
` : ''}
šŸ“… ${timestamp} šŸ’¬ ${report.message_count} messages analyzed šŸ“„ ${report.filename}
`; }); html += '
'; container.innerHTML = html; } async function loadBlockedUsers() { try { const result = await apiCall('/dms/blocked-users'); // Hide DM users list and show blocked users section document.getElementById('dm-users-list').style.display = 'none'; document.getElementById('blocked-users-section').style.display = 'block'; displayBlockedUsers(result.blocked_users); } catch (error) { console.error('Failed to load blocked users:', error); } } function hideBlockedUsers() { // Show DM users list and hide blocked users section document.getElementById('dm-users-list').style.display = 'block'; document.getElementById('blocked-users-section').style.display = 'none'; loadDMUsers(); // Refresh DM users } function displayBlockedUsers(blockedUsers) { const container = document.getElementById('blocked-users-list'); if (!blockedUsers || blockedUsers.length === 0) { container.innerHTML = '

No blocked users.

'; return; } let html = '
'; blockedUsers.forEach(user => { html += `

🚫 ${user.username}

ID: ${user.user_id}

Blocked: ${new Date(user.blocked_at).toLocaleString()}

Blocked by: ${user.blocked_by}

`; }); html += '
'; container.innerHTML = html; } async function exportAllDMs() { try { const result = await apiCall('/dms/users'); let exportCount = 0; for (const user of (result.users || [])) { try { await exportUserDMs(user.user_id); exportCount++; } catch (e) { console.error(`Failed to export DMs for user ${user.user_id}:`, e); } } showNotification(`Exported DMs for ${exportCount} users`); } catch (error) { console.error('Failed to export all DMs:', error); } }