feat(server): email notifications (#8447)

* feat(server): add `react-mail` as mail template engine and `nodemailer`

* feat(server): add `smtp` related configs to `SystemConfig`

* feat(web): add page for SMTP settings

* feat(server): add `react-email.adapter`

This adapter render the React-Email into HTML and plain/text email.
The output is set as the body of the email.

* feat(server): add `MailRepository` and `MailService`

Allow to use the NestJS-modules-mailer module to send SMTP emails.
This is the base transport for the `NotificationRepository`

* feat(server): register the job dispatcher and Job for async email

This allows to queue email sending jobs for the `EmailService`.

* feat(server): add `NotificationRepository` and `NotificationService`

This act as a middleware to properly route the notification to the right transport.
As POC I've only implemented a simple SMTP transport.

* feat(server): add `welcome` email template

* feat(server): add the first notification on `createUser` in `UserService`

This trigger an event for the `NotificationRepository` that once processes
by using the global config and per-user config will carry the payload to the right notification transport.

* chore: clean up

* chore: clean up web

* fix: type errors"

* fix package lock

* fix mail sending, option to ignore certs

* chore: open api

* chore: clean up

* remove unused import

* feat: email feature flag

* chore: remove unused interface

* small styling

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
Nicolò 2024-05-02 16:43:18 +02:00 committed by GitHub
parent 4b86c7a298
commit 9bce3417e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 6499 additions and 371 deletions

View file

@ -16,6 +16,7 @@ class CreateUserDto {
required this.email,
this.memoriesEnabled,
required this.name,
this.notify,
required this.password,
this.quotaSizeInBytes,
this.shouldChangePassword,
@ -34,6 +35,14 @@ class CreateUserDto {
String name;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? notify;
String password;
/// Minimum value: 1
@ -54,6 +63,7 @@ class CreateUserDto {
other.email == email &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
other.notify == notify &&
other.password == password &&
other.quotaSizeInBytes == quotaSizeInBytes &&
other.shouldChangePassword == shouldChangePassword &&
@ -65,13 +75,14 @@ class CreateUserDto {
(email.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(name.hashCode) +
(notify == null ? 0 : notify!.hashCode) +
(password.hashCode) +
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
(shouldChangePassword == null ? 0 : shouldChangePassword!.hashCode) +
(storageLabel == null ? 0 : storageLabel!.hashCode);
@override
String toString() => 'CreateUserDto[email=$email, memoriesEnabled=$memoriesEnabled, name=$name, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
String toString() => 'CreateUserDto[email=$email, memoriesEnabled=$memoriesEnabled, name=$name, notify=$notify, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@ -82,6 +93,11 @@ class CreateUserDto {
// json[r'memoriesEnabled'] = null;
}
json[r'name'] = this.name;
if (this.notify != null) {
json[r'notify'] = this.notify;
} else {
// json[r'notify'] = null;
}
json[r'password'] = this.password;
if (this.quotaSizeInBytes != null) {
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
@ -112,6 +128,7 @@ class CreateUserDto {
email: mapValueOfType<String>(json, r'email')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name')!,
notify: mapValueOfType<bool>(json, r'notify'),
password: mapValueOfType<String>(json, r'password')!,
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword'),