refactor(notification): make username and password optional (smtp) (#126)
This commit is contained in:
parent
ef8fd7228f
commit
c3acc26e05
5 changed files with 83 additions and 31 deletions
|
|
@ -164,6 +164,11 @@ export type ListVolumesResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -191,7 +196,7 @@ export type ListVolumesResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
@ -211,6 +216,11 @@ export type CreateVolumeData = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -255,6 +265,11 @@ export type CreateVolumeResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -282,7 +297,7 @@ export type CreateVolumeResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -302,6 +317,11 @@ export type TestConnectionData = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -399,6 +419,11 @@ export type GetVolumeResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -426,7 +451,7 @@ export type GetVolumeResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -448,6 +473,11 @@ export type UpdateVolumeData = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -501,6 +531,11 @@ export type UpdateVolumeResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -528,7 +563,7 @@ export type UpdateVolumeResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -1397,6 +1432,11 @@ export type ListBackupSchedulesResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -1424,7 +1464,7 @@ export type ListBackupSchedulesResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
volumeId: number;
|
volumeId: number;
|
||||||
|
|
@ -1636,6 +1676,11 @@ export type GetBackupScheduleResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -1663,7 +1708,7 @@ export type GetBackupScheduleResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
volumeId: number;
|
volumeId: number;
|
||||||
|
|
@ -1856,6 +1901,11 @@ export type GetBackupScheduleForVolumeResponses = {
|
||||||
version: '3' | '4' | '4.1';
|
version: '3' | '4' | '4.1';
|
||||||
port?: number;
|
port?: number;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
} | {
|
||||||
|
backend: 'rclone';
|
||||||
|
path: string;
|
||||||
|
remote: string;
|
||||||
|
readOnly?: boolean;
|
||||||
} | {
|
} | {
|
||||||
backend: 'smb';
|
backend: 'smb';
|
||||||
password: string;
|
password: string;
|
||||||
|
|
@ -1883,7 +1933,7 @@ export type GetBackupScheduleForVolumeResponses = {
|
||||||
name: string;
|
name: string;
|
||||||
shortId: string;
|
shortId: string;
|
||||||
status: 'error' | 'mounted' | 'unmounted';
|
status: 'error' | 'mounted' | 'unmounted';
|
||||||
type: 'directory' | 'nfs' | 'smb' | 'webdav';
|
type: 'directory' | 'nfs' | 'rclone' | 'smb' | 'webdav';
|
||||||
updatedAt: number;
|
updatedAt: number;
|
||||||
};
|
};
|
||||||
volumeId: number;
|
volumeId: number;
|
||||||
|
|
@ -1987,13 +2037,13 @@ export type GetScheduleNotificationsResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2077,13 +2127,13 @@ export type UpdateScheduleNotificationsResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2380,13 +2430,13 @@ export type ListNotificationDestinationsResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2441,13 +2491,13 @@ export type CreateNotificationDestinationData = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2501,13 +2551,13 @@ export type CreateNotificationDestinationResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2608,13 +2658,13 @@ export type GetNotificationDestinationResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2669,13 +2719,13 @@ export type UpdateNotificationDestinationData = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
@ -2739,13 +2789,13 @@ export type UpdateNotificationDestinationResponses = {
|
||||||
type: 'telegram';
|
type: 'telegram';
|
||||||
} | {
|
} | {
|
||||||
from: string;
|
from: string;
|
||||||
password: string;
|
|
||||||
smtpHost: string;
|
smtpHost: string;
|
||||||
smtpPort: number;
|
smtpPort: number;
|
||||||
to: Array<string>;
|
to: Array<string>;
|
||||||
type: 'email';
|
type: 'email';
|
||||||
useTLS: boolean;
|
useTLS: boolean;
|
||||||
username: string;
|
password?: string;
|
||||||
|
username?: string;
|
||||||
} | {
|
} | {
|
||||||
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
priority: 'default' | 'high' | 'low' | 'max' | 'min';
|
||||||
topic: string;
|
topic: string;
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
|
||||||
name="username"
|
name="username"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Username</FormLabel>
|
<FormLabel>Username (Optional)</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} placeholder="user@example.com" />
|
<Input {...field} placeholder="user@example.com" />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
@ -211,7 +211,7 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue
|
||||||
name="password"
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Password</FormLabel>
|
<FormLabel>Password (Optional)</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} type="password" placeholder="••••••••" />
|
<Input {...field} type="password" placeholder="••••••••" />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export const emailNotificationConfigSchema = type({
|
||||||
type: "'email'",
|
type: "'email'",
|
||||||
smtpHost: "string",
|
smtpHost: "string",
|
||||||
smtpPort: "1 <= number <= 65535",
|
smtpPort: "1 <= number <= 65535",
|
||||||
username: "string",
|
username: "string?",
|
||||||
password: "string",
|
password: "string?",
|
||||||
from: "string",
|
from: "string",
|
||||||
to: "string[]",
|
to: "string[]",
|
||||||
useTLS: "boolean",
|
useTLS: "boolean",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import type { NotificationConfig } from "~/schemas/notifications";
|
import type { NotificationConfig } from "~/schemas/notifications";
|
||||||
|
|
||||||
export function buildEmailShoutrrrUrl(config: Extract<NotificationConfig, { type: "email" }>): string {
|
export function buildEmailShoutrrrUrl(config: Extract<NotificationConfig, { type: "email" }>): string {
|
||||||
const auth = `${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}`;
|
const auth = config.username && config.password
|
||||||
|
? `${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}@`
|
||||||
|
: "";
|
||||||
const host = `${config.smtpHost}:${config.smtpPort}`;
|
const host = `${config.smtpHost}:${config.smtpPort}`;
|
||||||
const toRecipients = config.to.map((email) => encodeURIComponent(email)).join(",");
|
const toRecipients = config.to.map((email) => encodeURIComponent(email)).join(",");
|
||||||
const useStartTLS = config.useTLS ? "yes" : "no";
|
const useStartTLS = config.useTLS ? "yes" : "no";
|
||||||
|
|
||||||
return `smtp://${auth}@${host}/?from=${encodeURIComponent(config.from)}&to=${toRecipients}&starttls=${useStartTLS}`;
|
return `smtp://${auth}${host}/?from=${encodeURIComponent(config.from)}&to=${toRecipients}&starttls=${useStartTLS}`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ async function encryptSensitiveFields(config: NotificationConfig): Promise<Notif
|
||||||
case "email":
|
case "email":
|
||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
password: await cryptoUtils.encrypt(config.password),
|
password: config.password ? await cryptoUtils.encrypt(config.password) : undefined,
|
||||||
};
|
};
|
||||||
case "slack":
|
case "slack":
|
||||||
return {
|
return {
|
||||||
|
|
@ -85,7 +85,7 @@ async function decryptSensitiveFields(config: NotificationConfig): Promise<Notif
|
||||||
case "email":
|
case "email":
|
||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
password: await cryptoUtils.decrypt(config.password),
|
password: config.password ? await cryptoUtils.decrypt(config.password) : undefined,
|
||||||
};
|
};
|
||||||
case "slack":
|
case "slack":
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue