docs: explain Teams API limitation for message deletion
- Microsoft Teams Graph API does not support DELETE on channel messages - This is a platform limitation, not an application error - Updated UI to show clear warning about Teams API limitation - Updated error messages to guide users on alternatives: - Delete via Teams client UI - Use delegated token with ChatMessage.ReadWrite.All permission - HTTP 405 (Method Not Allowed) is the expected response from Graph API
This commit is contained in:
@@ -4,6 +4,7 @@ import { serveStatic } from 'hono/bun';
|
||||
import { cors } from 'hono/cors';
|
||||
import PocketBase from 'pocketbase';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { listTeamChannels, listChannelMessages, listTeamChannelsWithToken, listChannelMessagesWithToken, deleteChannelMessage, deleteChannelMessageWithToken } from './services/teams/messages.ts';
|
||||
import { mkdir, appendFile } from 'fs/promises';
|
||||
import { existsSync } from 'fs';
|
||||
import path from 'path';
|
||||
@@ -753,6 +754,88 @@ app.get('/api/health', (c) => {
|
||||
});
|
||||
});
|
||||
|
||||
// List channels in a Team (to obtain Channel IDs)
|
||||
app.get('/api/teams/:teamId/channels', async (c) => {
|
||||
const teamId = c.req.param('teamId');
|
||||
try {
|
||||
const authHeader = c.req.header('authorization') || c.req.header('Authorization');
|
||||
const bearer = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null;
|
||||
const channels = bearer
|
||||
? await listTeamChannelsWithToken(teamId, bearer)
|
||||
: await listTeamChannels(teamId);
|
||||
return c.json({ success: true, teamId, channels });
|
||||
} catch (err: any) {
|
||||
console.error('⚠️ Failed to list channels:', err);
|
||||
await logError('Graph List Channels', err, { teamId });
|
||||
return c.json({ success: false, message: err.message || 'Failed to list channels' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// List messages in a channel (to obtain message IDs)
|
||||
app.get('/api/teams/:teamId/channels/:channelId/messages', async (c) => {
|
||||
const teamId = c.req.param('teamId');
|
||||
const channelId = c.req.param('channelId');
|
||||
const top = Number(c.req.query('top') || '50');
|
||||
try {
|
||||
const authHeader = c.req.header('authorization') || c.req.header('Authorization');
|
||||
const bearer = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null;
|
||||
const messages = bearer
|
||||
? await listChannelMessagesWithToken(teamId, channelId, Math.min(top, 50), bearer)
|
||||
: await listChannelMessages(teamId, channelId, Math.min(top, 50));
|
||||
return c.json({ success: true, teamId, channelId, count: messages.length, messages });
|
||||
} catch (err: any) {
|
||||
console.error('⚠️ Failed to list messages:', err);
|
||||
await logError('Graph List Messages', err, { teamId, channelId });
|
||||
return c.json({ success: false, message: err.message || 'Failed to list messages' }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete a message in a channel (requires appropriate Graph permissions)
|
||||
app.delete('/api/teams/:teamId/channels/:channelId/messages/:messageId', async (c) => {
|
||||
const teamId = c.req.param('teamId');
|
||||
const channelId = c.req.param('channelId');
|
||||
const messageId = c.req.param('messageId');
|
||||
try {
|
||||
const authHeader = c.req.header('authorization') || c.req.header('Authorization');
|
||||
const bearer = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null;
|
||||
const tokenType = bearer ? 'Bearer token provided' : 'Using app credentials';
|
||||
console.log(`🗑️ DELETE request: ${tokenType} | Team: ${teamId} | Channel: ${channelId} | Message: ${messageId}`);
|
||||
if (bearer) {
|
||||
await deleteChannelMessageWithToken(teamId, channelId, messageId, bearer);
|
||||
} else {
|
||||
await deleteChannelMessage(teamId, channelId, messageId);
|
||||
}
|
||||
console.log(`✅ Successfully deleted message: ${messageId}`);
|
||||
return c.json({ success: true, teamId, channelId, messageId });
|
||||
} catch (err: any) {
|
||||
const errMsg = err?.message || JSON.stringify(err);
|
||||
const errStatus = err?.status || err?.statusCode;
|
||||
|
||||
// Check if it's the Teams API limitation error
|
||||
const isTeamsLimitation = errMsg?.includes('Teams API limitation') || errMsg?.includes('not supported');
|
||||
|
||||
console.error(`${isTeamsLimitation ? '⚠️' : '❌'} Failed to delete message: ${errMsg} | Status: ${errStatus}`);
|
||||
if (isTeamsLimitation) {
|
||||
console.log(`📝 Note: This is a Microsoft Teams platform limitation, not an application error`);
|
||||
}
|
||||
|
||||
await logError('Graph Delete Message', err, {
|
||||
teamId,
|
||||
channelId,
|
||||
messageId,
|
||||
error: errMsg,
|
||||
status: errStatus,
|
||||
isTeamsLimitation
|
||||
});
|
||||
|
||||
return c.json({
|
||||
success: false,
|
||||
message: errMsg || 'Failed to delete message',
|
||||
isTeamsLimitation: isTeamsLimitation || false
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Test route: sends an exact sample Adaptive Card payload (no envelope)
|
||||
app.post('/api/test-notification', async (c) => {
|
||||
const webhook = process.env.POWER_AUTOMATE_WEBHOOK_URL || process.env.TEAMS_WEBHOOK_URL;
|
||||
|
||||
Reference in New Issue
Block a user