fix: can't set proxy for email account (IMAP) #326

This commit is contained in:
rustmailer
2026-07-20 23:00:36 +08:00
parent c6da79cdb0
commit 664ac2fe55
8 changed files with 41 additions and 22 deletions
-1
View File
@@ -255,7 +255,6 @@ impl From<AccountV3> for AccountModel {
created_at: value.created_at, created_at: value.created_at,
updated_at: value.updated_at, updated_at: value.updated_at,
created_by: value.created_by, created_by: value.created_by,
use_proxy: value.use_proxy,
use_dangerous: value.use_dangerous, use_dangerous: value.use_dangerous,
pgp_key: value.pgp_key, pgp_key: value.pgp_key,
imap_quota_window: None, imap_quota_window: None,
-6
View File
@@ -300,7 +300,6 @@ pub struct Account {
pub created_at: i64, pub created_at: i64,
pub updated_at: i64, pub updated_at: i64,
pub created_by: u64, //user id pub created_by: u64, //user id
pub use_proxy: Option<u64>,
pub use_dangerous: bool, pub use_dangerous: bool,
pub pgp_key: Option<String>, pub pgp_key: Option<String>,
pub imap_quota_bytes: Option<u64>, pub imap_quota_bytes: Option<u64>,
@@ -345,7 +344,6 @@ impl Account {
download_interval_min: request.download_interval_min, download_interval_min: request.download_interval_min,
created_at: utc_now!(), created_at: utc_now!(),
updated_at: utc_now!(), updated_at: utc_now!(),
use_proxy: request.use_proxy,
use_dangerous: request.use_dangerous, use_dangerous: request.use_dangerous,
pgp_key: request.pgp_key, pgp_key: request.pgp_key,
created_by: user_id, created_by: user_id,
@@ -657,10 +655,6 @@ impl Account {
if let Some(max_email_size_bytes) = request.max_email_size_bytes { if let Some(max_email_size_bytes) = request.max_email_size_bytes {
new.max_email_size_bytes = Some(max_email_size_bytes); new.max_email_size_bytes = Some(max_email_size_bytes);
} }
if let Some(use_proxy) = request.use_proxy {
new.use_proxy = Some(use_proxy);
}
} }
if matches!(old.account_type, AccountType::NoSync) { if matches!(old.account_type, AccountType::NoSync) {
-6
View File
@@ -51,7 +51,6 @@ pub struct AccountCreateRequest {
)] )]
pub download_batch_size: Option<u32>, pub download_batch_size: Option<u32>,
pub max_email_size_bytes: Option<u64>, pub max_email_size_bytes: Option<u64>,
pub use_proxy: Option<u64>,
pub use_dangerous: bool, pub use_dangerous: bool,
pub pgp_key: Option<String>, pub pgp_key: Option<String>,
pub imap_quota_bytes: Option<u64>, pub imap_quota_bytes: Option<u64>,
@@ -188,11 +187,6 @@ pub struct AccountUpdateRequest {
)] )]
pub download_batch_size: Option<u32>, pub download_batch_size: Option<u32>,
pub max_email_size_bytes: Option<u64>, pub max_email_size_bytes: Option<u64>,
/// Optional proxy ID for establishing the connection to external APIs (e.g., Gmail, Outlook).
/// - If `None` or not provided, the client will connect directly to the API server.
/// - If `Some(proxy_id)`, the client will use the pre-configured proxy with the given ID for API requests.
pub use_proxy: Option<u64>,
pub use_dangerous: Option<bool>, pub use_dangerous: Option<bool>,
pub pgp_key: Option<String>, pub pgp_key: Option<String>,
-2
View File
@@ -51,7 +51,6 @@ pub struct AccountResp {
pub created_by: u64, //user id pub created_by: u64, //user id
pub created_user_name: String, pub created_user_name: String,
pub created_user_email: String, pub created_user_email: String,
pub use_proxy: Option<u64>,
pub use_dangerous: bool, pub use_dangerous: bool,
pub pgp_key: Option<String>, pub pgp_key: Option<String>,
pub imap_quota_bytes: Option<u64>, pub imap_quota_bytes: Option<u64>,
@@ -90,7 +89,6 @@ impl AccountResp {
created_user_email: user created_user_email: user
.map(|u| u.email.clone()) .map(|u| u.email.clone())
.unwrap_or_else(|| "N/A".to_string()), .unwrap_or_else(|| "N/A".to_string()),
use_proxy: account.use_proxy,
use_dangerous: account.use_dangerous, use_dangerous: account.use_dangerous,
pgp_key: account.pgp_key, pgp_key: account.pgp_key,
imap_quota_bytes: account.imap_quota_bytes, imap_quota_bytes: account.imap_quota_bytes,
-1
View File
@@ -152,7 +152,6 @@ export interface AccountModel {
created_user_email: string; created_user_email: string;
created_at: number; created_at: number;
updated_at: number; updated_at: number;
use_proxy?: number;
use_dangerous: boolean; use_dangerous: boolean;
pgp_key?: string; pgp_key?: string;
imap_quota_window?: QuotaWindow; imap_quota_window?: QuotaWindow;
+3 -1
View File
@@ -111,12 +111,14 @@ export function AccountNewPage() {
const onSubmit = useCallback( const onSubmit = useCallback(
(data: AccountFormValues) => { (data: AccountFormValues) => {
const { use_proxy, ...imapRest } = data.imap;
createMutation.mutate({ createMutation.mutate({
email: data.email, email: data.email,
account_name: data.account_name, account_name: data.account_name,
login_name: data.login_name, login_name: data.login_name,
imap: { imap: {
...data.imap, ...imapRest,
use_proxy,
auth: { auth: {
...data.imap.auth, ...data.imap.auth,
password: data.imap.auth.auth_type === 'OAuth2' ? undefined : data.imap.auth.password, password: data.imap.auth.auth_type === 'OAuth2' ? undefined : data.imap.auth.password,
@@ -44,15 +44,12 @@ const emptyImap = {
port: 0, port: 0,
encryption: "None" as const, encryption: "None" as const,
auth: { auth_type: "Password" as const, password: undefined }, auth: { auth_type: "Password" as const, password: undefined },
use_proxy: undefined, use_proxy: null,
}; };
function mapAccountToFormValues(account: AccountModel): AccountFormValues { function mapAccountToFormValues(account: AccountModel): AccountFormValues {
const imap = { ...(account.imap ?? emptyImap) }; const imap = { ...(account.imap ?? emptyImap) };
imap.auth = { ...imap.auth, password: undefined }; imap.auth = { ...imap.auth, password: undefined };
if ((imap as any).use_proxy === null) {
(imap as any).use_proxy = undefined;
}
return { return {
account_name: account.account_name ?? undefined, account_name: account.account_name ?? undefined,
@@ -137,12 +134,14 @@ export function AccountSettingsPage({ accountId }: AccountSettingsPageProps) {
const onSubmit = useCallback( const onSubmit = useCallback(
(data: AccountFormValues) => { (data: AccountFormValues) => {
const { use_proxy, ...imapRest } = data.imap;
const payload: Record<string, any> = { const payload: Record<string, any> = {
email: data.email, email: data.email,
account_name: data.account_name, account_name: data.account_name,
login_name: data.login_name, login_name: data.login_name,
imap: { imap: {
...data.imap, ...imapRest,
use_proxy,
auth: { auth: {
...data.imap.auth, ...data.imap.auth,
password: data.imap.auth.auth_type === 'OAuth2' password: data.imap.auth.auth_type === 'OAuth2'
@@ -37,6 +37,7 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { PasswordInput } from "@/components/password-input"; import { PasswordInput } from "@/components/password-input";
import { AccountFormValues } from "./schema"; import { AccountFormValues } from "./schema";
import useProxyList from "@/hooks/use-proxy";
interface TabServerProps { interface TabServerProps {
isEdit?: boolean; isEdit?: boolean;
@@ -46,6 +47,7 @@ export function TabServer({ isEdit }: TabServerProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const { control, watch } = useFormContext<AccountFormValues>(); const { control, watch } = useFormContext<AccountFormValues>();
const authType = watch('imap.auth.auth_type'); const authType = watch('imap.auth.auth_type');
const { proxyOptions } = useProxyList();
return ( return (
<div className="space-y-6"> <div className="space-y-6">
@@ -161,6 +163,38 @@ export function TabServer({ isEdit }: TabServerProps) {
/> />
)} )}
<FormField
control={control}
name="imap.use_proxy"
render={({ field }) => (
<FormItem>
<FormLabel>{t('accounts.useProxyOptional')}</FormLabel>
<Select
onValueChange={(v) => field.onChange(v === 'none' ? undefined : Number(v))}
defaultValue={field.value?.toString()}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder={t('accounts.selectProxy')}/>
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem key="none" value="none">{t('accounts.useNoProxy')}</SelectItem>
{proxyOptions.map((opt) => (
<SelectItem key={opt.value} value={opt.value}>
<span className="max-w-[280px] truncate block" title={opt.label}>
{opt.label}
</span>
</SelectItem>
))}
</SelectContent>
</Select>
<FormDescription>{t('accounts.imapProxy')}</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField <FormField
control={control} control={control}
name="use_dangerous" name="use_dangerous"