feat: add daily digest email notification module
Build and Push Multi-Platform Images / build-and-push (push) Successful in 50s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 50s
- New DailyDigestModule with scheduled summary email for open dashboard items - Extract StatsService from StatsController for reuse in digest - Add DailyDigestEnabled, UserEmail, UserPreferredUsername to UserSettings entity - Sync email/username from OIDC token on each get/update call - Add dailyDigestEnabled to UserSettingsDto and update API - Notifications tab in UserSettingsPage with enable toggle and "Jetzt senden" button Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ export interface UserSettingsDto {
|
||||
mailSignatureHtml: string | null;
|
||||
defaultLabelTemplateId: number | null;
|
||||
emailRecipientHistory: string[] | null;
|
||||
dailyDigestEnabled: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@@ -64,8 +65,16 @@ export class UserSettingsService {
|
||||
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8');
|
||||
}
|
||||
|
||||
async getSettings(userId: string): Promise<UserSettingsDto> {
|
||||
const entity = await this.repo.findOne({ where: { UserId: userId } });
|
||||
async getSettings(userId: string, email?: string, preferredUsername?: string): Promise<UserSettingsDto> {
|
||||
let entity = await this.repo.findOne({ where: { UserId: userId } });
|
||||
if (email || preferredUsername) {
|
||||
if (!entity) {
|
||||
entity = this.repo.create({ UserId: userId });
|
||||
}
|
||||
if (email) entity.UserEmail = email;
|
||||
if (preferredUsername) entity.UserPreferredUsername = preferredUsername;
|
||||
await this.repo.save(entity);
|
||||
}
|
||||
return this.toDto(entity);
|
||||
}
|
||||
|
||||
@@ -82,7 +91,10 @@ export class UserSettingsService {
|
||||
mailSignatureHtml?: string | null;
|
||||
defaultLabelTemplateId?: number | null;
|
||||
emailRecipientHistory?: string[] | null;
|
||||
dailyDigestEnabled?: boolean;
|
||||
},
|
||||
email?: string,
|
||||
preferredUsername?: string,
|
||||
): Promise<UserSettingsDto> {
|
||||
let entity = await this.repo.findOne({ where: { UserId: userId } });
|
||||
if (!entity) {
|
||||
@@ -101,6 +113,9 @@ export class UserSettingsService {
|
||||
if (data.mailSignatureHtml !== undefined) entity.MailSignatureHtml = data.mailSignatureHtml;
|
||||
if (data.defaultLabelTemplateId !== undefined) entity.DefaultLabelTemplateId = data.defaultLabelTemplateId;
|
||||
if (data.emailRecipientHistory !== undefined) entity.EmailRecipientHistory = data.emailRecipientHistory;
|
||||
if (data.dailyDigestEnabled !== undefined) entity.DailyDigestEnabled = data.dailyDigestEnabled;
|
||||
if (email) entity.UserEmail = email;
|
||||
if (preferredUsername) entity.UserPreferredUsername = preferredUsername;
|
||||
|
||||
await this.repo.save(entity);
|
||||
return this.toDto(entity);
|
||||
@@ -144,6 +159,12 @@ export class UserSettingsService {
|
||||
};
|
||||
}
|
||||
|
||||
async findAllDigestSubscribers(): Promise<UserSettings[]> {
|
||||
return this.repo.find({
|
||||
where: { DailyDigestEnabled: true },
|
||||
}).then(rows => rows.filter(r => !!r.UserEmail));
|
||||
}
|
||||
|
||||
async getAvailableSenders(userId: string): Promise<{ id: string; label: string }[]> {
|
||||
const defaultEmail = this.configService.get<string>('SMTP_FROM', 'paperless@localhost');
|
||||
const defaultName = this.configService.get<string>('SMTP_FROM_NAME', '');
|
||||
@@ -172,6 +193,7 @@ export class UserSettingsService {
|
||||
mailSignatureHtml: entity?.MailSignatureHtml ?? null,
|
||||
defaultLabelTemplateId: entity?.DefaultLabelTemplateId ?? null,
|
||||
emailRecipientHistory: entity?.EmailRecipientHistory ?? null,
|
||||
dailyDigestEnabled: entity?.DailyDigestEnabled ?? false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user