feat: Add OAuth email integration and production deployment config
- Add OAuthCredential model for storing Google/Microsoft OAuth tokens - Add email provider auto-detection endpoint (Gmail, Outlook, Yahoo, etc.) - Add EmailConfigWizard frontend component with step-by-step setup - Add OAuth flow endpoints for Google and Microsoft XOAUTH2 - Update production settings to make AWS, Sentry, Mailgun optional - Update Traefik config for wildcard subdomain routing - Add logo resize utility script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,25 @@ export interface FetchNowResult {
|
||||
processed: number;
|
||||
}
|
||||
|
||||
export interface EmailProviderDetectResult {
|
||||
success: boolean;
|
||||
email: string;
|
||||
domain: string;
|
||||
detected: boolean;
|
||||
detected_via?: 'domain_lookup' | 'mx_record';
|
||||
provider: 'google' | 'microsoft' | 'yahoo' | 'apple' | 'aol' | 'zoho' | 'protonmail' | 'unknown';
|
||||
display_name: string;
|
||||
imap_host?: string;
|
||||
imap_port?: number;
|
||||
smtp_host?: string;
|
||||
smtp_port?: number;
|
||||
oauth_supported: boolean;
|
||||
message?: string;
|
||||
notes?: string;
|
||||
suggested_imap_port?: number;
|
||||
suggested_smtp_port?: number;
|
||||
}
|
||||
|
||||
export interface IncomingTicketEmail {
|
||||
id: number;
|
||||
message_id: string;
|
||||
@@ -167,3 +186,77 @@ export const reprocessIncomingEmail = async (id: number): Promise<{
|
||||
const response = await apiClient.post(`/api/tickets/incoming-emails/${id}/reprocess/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect email provider from email address
|
||||
* Auto-detects Gmail, Outlook, Yahoo, iCloud, etc. from domain
|
||||
* Also checks MX records for custom domains using Google Workspace or Microsoft 365
|
||||
*/
|
||||
export const detectEmailProvider = async (email: string): Promise<EmailProviderDetectResult> => {
|
||||
const response = await apiClient.post('/api/tickets/email-settings/detect/', { email });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// OAuth types and functions
|
||||
export interface OAuthStatusResult {
|
||||
google: { configured: boolean };
|
||||
microsoft: { configured: boolean };
|
||||
}
|
||||
|
||||
export interface OAuthInitiateResult {
|
||||
success: boolean;
|
||||
authorization_url?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface OAuthCredential {
|
||||
id: number;
|
||||
provider: 'google' | 'microsoft';
|
||||
email: string;
|
||||
purpose: string;
|
||||
is_valid: boolean;
|
||||
is_expired: boolean;
|
||||
last_used_at: string | null;
|
||||
last_error: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OAuth configuration status
|
||||
*/
|
||||
export const getOAuthStatus = async (): Promise<OAuthStatusResult> => {
|
||||
const response = await apiClient.get('/api/oauth/status/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initiate Google OAuth flow
|
||||
*/
|
||||
export const initiateGoogleOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
|
||||
const response = await apiClient.post('/api/oauth/google/initiate/', { purpose });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initiate Microsoft OAuth flow
|
||||
*/
|
||||
export const initiateMicrosoftOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
|
||||
const response = await apiClient.post('/api/oauth/microsoft/initiate/', { purpose });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* List OAuth credentials
|
||||
*/
|
||||
export const getOAuthCredentials = async (): Promise<OAuthCredential[]> => {
|
||||
const response = await apiClient.get('/api/oauth/credentials/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete OAuth credential
|
||||
*/
|
||||
export const deleteOAuthCredential = async (id: number): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await apiClient.delete(`/api/oauth/credentials/${id}/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user