feat: mailbox remediation via Graph Mail.ReadWrite — search + move to Deleted Items from analysis dialog
- Add searchMailboxMessages, deleteMailboxMessage, moveToDeletedItems to MsGraphClient - POST /api/mimecast/mailbox-remediate: search, move, delete actions with permission error handling - DeliveredAnalysisDialog: Remove from mailbox panel with search → confirm → delete flow - Shows matching messages in mailbox with checkboxes, received time, read/unread status - Moves selected to Deleted Items (recoverable) via Graph API - Surfaces clear permission guidance if Mail.ReadWrite not yet granted
This commit is contained in:
parent
c2ebbe586b
commit
bc3904de4e
3 changed files with 316 additions and 1 deletions
|
|
@ -330,6 +330,82 @@ export class MsGraphClient {
|
|||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /users/{user}/messages — search by sender and/or subject in a date range.
|
||||
* Requires Mail.ReadWrite application permission.
|
||||
*/
|
||||
async searchMailboxMessages(options: {
|
||||
userEmail: string;
|
||||
fromAddress?: string;
|
||||
subject?: string;
|
||||
receivedAfter?: string;
|
||||
receivedBefore?: string;
|
||||
maxResults?: number;
|
||||
}): Promise<{ id: string; subject: string; from: string; receivedDateTime: string; isRead: boolean }[]> {
|
||||
const filters: string[] = [];
|
||||
if (options.fromAddress) {
|
||||
filters.push(`from/emailAddress/address eq '${options.fromAddress.replace(/'/g, "''")}'`);
|
||||
}
|
||||
if (options.subject) {
|
||||
filters.push(`contains(subject,'${options.subject.replace(/'/g, "''")}') `);
|
||||
}
|
||||
if (options.receivedAfter) {
|
||||
filters.push(`receivedDateTime ge ${options.receivedAfter}`);
|
||||
}
|
||||
if (options.receivedBefore) {
|
||||
filters.push(`receivedDateTime le ${options.receivedBefore}`);
|
||||
}
|
||||
if (!filters.length) throw new Error('At least one search filter required');
|
||||
|
||||
const top = Math.min(options.maxResults ?? 50, 100);
|
||||
const qs = `$filter=${encodeURIComponent(filters.join(' and '))}&$select=id,subject,from,receivedDateTime,isRead&$top=${top}&$orderby=receivedDateTime desc`;
|
||||
const url = `/users/${encodeURIComponent(options.userEmail)}/messages?${qs}`;
|
||||
|
||||
const data = await this.fetchJson<{ value: any[] }>(url);
|
||||
return (data.value ?? []).map(m => ({
|
||||
id: m.id,
|
||||
subject: m.subject ?? '',
|
||||
from: m.from?.emailAddress?.address ?? '',
|
||||
receivedDateTime: m.receivedDateTime ?? '',
|
||||
isRead: m.isRead ?? false,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /users/{user}/messages/{messageId}
|
||||
* Permanently deletes a message. Requires Mail.ReadWrite application permission.
|
||||
*/
|
||||
async deleteMailboxMessage(userEmail: string, messageId: string): Promise<void> {
|
||||
const token = await this.getToken();
|
||||
const url = `https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userEmail)}/messages/${encodeURIComponent(messageId)}`;
|
||||
const res = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (res.status === 204) return;
|
||||
if (res.status === 404) return; // already gone
|
||||
const text = await res.text();
|
||||
throw new Error(`Graph delete failed ${res.status}: ${text}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a message to Deleted Items (soft delete — recoverable).
|
||||
* Requires Mail.ReadWrite application permission.
|
||||
*/
|
||||
async moveToDeletedItems(userEmail: string, messageId: string): Promise<void> {
|
||||
const token = await this.getToken();
|
||||
const url = `https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userEmail)}/messages/${encodeURIComponent(messageId)}/move`;
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ destinationId: 'deleteditems' }),
|
||||
});
|
||||
if (res.ok) return;
|
||||
if (res.status === 404) return;
|
||||
const text = await res.text();
|
||||
throw new Error(`Graph move failed ${res.status}: ${text}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get calendar events for a user in a date range (paginated).
|
||||
* Returns empty array and logs if the mailbox is not Exchange Online (graceful degradation).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue