feat: Multi-email ticketing system with platform email addresses
- Add PlatformEmailAddress model for managing platform-level email addresses - Add TicketEmailAddress model for tenant-level email addresses - Create MailServerService for IMAP integration with mail.talova.net - Implement PlatformEmailReceiver for processing incoming platform emails - Add email autoconfiguration for Mozilla, Microsoft, and Apple clients - Add configurable email polling interval in platform settings - Add "Check Emails" button on support page for manual refresh - Add ticket counts to status tabs on support page - Add platform email addresses management page - Add Privacy Policy and Terms of Service pages - Add robots.txt for SEO - Restrict email addresses to smoothschedule.com domain only 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
250
frontend/src/api/platformEmailAddresses.ts
Normal file
250
frontend/src/api/platformEmailAddresses.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* API client for Platform Email Addresses
|
||||
* These are email addresses managed directly on the mail.talova.net server
|
||||
*/
|
||||
|
||||
import apiClient from './client';
|
||||
|
||||
export interface PlatformEmailAddress {
|
||||
id: number;
|
||||
display_name: string;
|
||||
sender_name: string;
|
||||
effective_sender_name: string;
|
||||
local_part: string;
|
||||
domain: string;
|
||||
email_address: string;
|
||||
color: string;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
mail_server_synced: boolean;
|
||||
last_sync_error?: string;
|
||||
last_synced_at?: string;
|
||||
last_check_at?: string;
|
||||
emails_processed_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
imap_settings?: {
|
||||
host: string;
|
||||
port: number;
|
||||
use_ssl: boolean;
|
||||
username: string;
|
||||
folder: string;
|
||||
};
|
||||
smtp_settings?: {
|
||||
host: string;
|
||||
port: number;
|
||||
use_tls: boolean;
|
||||
use_ssl: boolean;
|
||||
username: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AssignedUser {
|
||||
id: number;
|
||||
email: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
full_name: string;
|
||||
}
|
||||
|
||||
export interface AssignableUser extends AssignedUser {
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface PlatformEmailAddressListItem {
|
||||
id: number;
|
||||
display_name: string;
|
||||
sender_name: string;
|
||||
effective_sender_name: string;
|
||||
local_part: string;
|
||||
domain: string;
|
||||
email_address: string;
|
||||
color: string;
|
||||
assigned_user?: AssignedUser | null;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
mail_server_synced: boolean;
|
||||
last_check_at?: string;
|
||||
emails_processed_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface PlatformEmailAddressCreate {
|
||||
display_name: string;
|
||||
sender_name?: string;
|
||||
assigned_user_id?: number | null;
|
||||
local_part: string;
|
||||
domain: string;
|
||||
color: string;
|
||||
password: string;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
}
|
||||
|
||||
export interface PlatformEmailAddressUpdate {
|
||||
display_name?: string;
|
||||
sender_name?: string;
|
||||
assigned_user_id?: number | null;
|
||||
color?: string;
|
||||
password?: string;
|
||||
is_active?: boolean;
|
||||
is_default?: boolean;
|
||||
}
|
||||
|
||||
export interface EmailDomain {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface TestConnectionResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface SyncResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
mail_server_synced?: boolean;
|
||||
last_synced_at?: string;
|
||||
last_sync_error?: string;
|
||||
}
|
||||
|
||||
export interface MailServerAccountsResponse {
|
||||
success: boolean;
|
||||
accounts: { email: string; raw_line: string }[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface ImportFromMailServerResponse {
|
||||
success: boolean;
|
||||
imported: { id: number; email: string; display_name: string }[];
|
||||
imported_count: number;
|
||||
skipped: { email: string; reason: string }[];
|
||||
skipped_count: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all platform email addresses
|
||||
*/
|
||||
export const getPlatformEmailAddresses = async (): Promise<PlatformEmailAddressListItem[]> => {
|
||||
const response = await apiClient.get('/platform/email-addresses/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a specific platform email address by ID
|
||||
*/
|
||||
export const getPlatformEmailAddress = async (id: number): Promise<PlatformEmailAddress> => {
|
||||
const response = await apiClient.get(`/platform/email-addresses/${id}/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new platform email address
|
||||
*/
|
||||
export const createPlatformEmailAddress = async (
|
||||
data: PlatformEmailAddressCreate
|
||||
): Promise<PlatformEmailAddress> => {
|
||||
const response = await apiClient.post('/platform/email-addresses/', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update an existing platform email address
|
||||
*/
|
||||
export const updatePlatformEmailAddress = async (
|
||||
id: number,
|
||||
data: PlatformEmailAddressUpdate
|
||||
): Promise<PlatformEmailAddress> => {
|
||||
const response = await apiClient.patch(`/platform/email-addresses/${id}/`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a platform email address (also removes from mail server)
|
||||
*/
|
||||
export const deletePlatformEmailAddress = async (id: number): Promise<void> => {
|
||||
await apiClient.delete(`/platform/email-addresses/${id}/`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove email address from database only (keeps mail server account)
|
||||
*/
|
||||
export const removeLocalPlatformEmailAddress = async (id: number): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await apiClient.post(`/platform/email-addresses/${id}/remove_local/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync email address to mail server
|
||||
*/
|
||||
export const syncPlatformEmailAddress = async (id: number): Promise<SyncResponse> => {
|
||||
const response = await apiClient.post(`/platform/email-addresses/${id}/sync/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test IMAP connection for a platform email address
|
||||
*/
|
||||
export const testImapConnection = async (id: number): Promise<TestConnectionResponse> => {
|
||||
const response = await apiClient.post(`/platform/email-addresses/${id}/test_imap/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test SMTP connection for a platform email address
|
||||
*/
|
||||
export const testSmtpConnection = async (id: number): Promise<TestConnectionResponse> => {
|
||||
const response = await apiClient.post(`/platform/email-addresses/${id}/test_smtp/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a platform email address as the default
|
||||
*/
|
||||
export const setAsDefault = async (id: number): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await apiClient.post(`/platform/email-addresses/${id}/set_as_default/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test SSH connection to the mail server
|
||||
*/
|
||||
export const testMailServerConnection = async (): Promise<TestConnectionResponse> => {
|
||||
const response = await apiClient.post('/platform/email-addresses/test_mail_server/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all email accounts from the mail server
|
||||
*/
|
||||
export const getMailServerAccounts = async (): Promise<MailServerAccountsResponse> => {
|
||||
const response = await apiClient.get('/platform/email-addresses/mail_server_accounts/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get available email domains
|
||||
*/
|
||||
export const getAvailableDomains = async (): Promise<{ domains: EmailDomain[] }> => {
|
||||
const response = await apiClient.get('/platform/email-addresses/available_domains/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get assignable users (platform users who can be assigned to email addresses)
|
||||
*/
|
||||
export const getAssignableUsers = async (): Promise<{ users: AssignableUser[] }> => {
|
||||
const response = await apiClient.get('/platform/email-addresses/assignable_users/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Import email addresses from the mail server
|
||||
*/
|
||||
export const importFromMailServer = async (): Promise<ImportFromMailServerResponse> => {
|
||||
const response = await apiClient.post('/platform/email-addresses/import_from_mail_server/');
|
||||
return response.data;
|
||||
};
|
||||
Reference in New Issue
Block a user