diff --git a/bot/src/bot/translation/de.json b/bot/src/bot/translation/de.json index 60b069a8..d6631bd1 100644 --- a/bot/src/bot/translation/de.json +++ b/bot/src/bot/translation/de.json @@ -2,22 +2,22 @@ "api": { "api": { "test_mail": { - "message": "Dies ist eine Test-Mail vom Kruemelmonster Web Interface\r\nGesendet von {}-{}", + "message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\r\nGesendet von {}-{}", "subject": "Krümelmonster Web Interface Test-Mail" } }, "auth": { "confirmation": { - "message": "Öffne den Link, um die E-Mail zu bestätigen:\n{}auth/register/{}", + "message": "Öffne den Link, um die E-Mail zu bestätigen:\r\n{}auth/register/{}", "subject": "E-Mail für {} {} bestätigen" }, "forgot_password": { - "message": "Öffne den Link, um das Passwort zu ändern:\n{}auth/forgot-password/{}", + "message": "Öffne den Link, um das Passwort zu ändern:\r\n{}auth/forgot-password/{}", "subject": "Passwort für {} {} zurücksetzen" } }, "mail": { - "automatic_mail": "\n\nDies ist eine automatische E-Mail.\nGesendet von {}-{}@{}" + "automatic_mail": "\r\n\r\nDies ist eine automatische E-Mail.\r\nGesendet von {}-{}@{}" } }, "common": { diff --git a/bot/src/bot_api/abc/auth_service_abc.py b/bot/src/bot_api/abc/auth_service_abc.py index 1ba5fbbb..c72d0d14 100644 --- a/bot/src/bot_api/abc/auth_service_abc.py +++ b/bot/src/bot_api/abc/auth_service_abc.py @@ -114,3 +114,7 @@ class AuthServiceABC(ABC): @abstractmethod async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass + + @abstractmethod + async def resend_confirmation_email_by_mail(self, mail: str): + pass diff --git a/bot/src/bot_api/controller/auth_controller.py b/bot/src/bot_api/controller/auth_controller.py index 085f03a6..6f13abdc 100644 --- a/bot/src/bot_api/controller/auth_controller.py +++ b/bot/src/bot_api/controller/auth_controller.py @@ -84,6 +84,11 @@ class AuthController: self._auth_service.add_auth_user(dto) return "", 200 + @Route.post(f"{BasePath}/resend-confirmation-email-by-mail/") + async def resend_confirmation_email_by_user_id(self, mail: str): + await self._auth_service.resend_confirmation_email_by_mail(mail) + return "", 200 + @Route.post(f"{BasePath}/register-by-id/") async def register_id(self, id: str): result = await self._auth_service.confirm_email_async(id) diff --git a/bot/src/bot_api/controller/auth_discord_controller.py b/bot/src/bot_api/controller/auth_discord_controller.py index 8ad193cc..6c3b1d0f 100644 --- a/bot/src/bot_api/controller/auth_discord_controller.py +++ b/bot/src/bot_api/controller/auth_discord_controller.py @@ -16,6 +16,7 @@ from bot_api.api import Api from bot_api.configuration.discord_authentication_settings import ( DiscordAuthenticationSettings, ) +from bot_api.exception.service_exception import ServiceException from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.route.route import Route @@ -90,5 +91,10 @@ class AuthDiscordController: AuthRoleEnum.normal, ) - result = await self._auth_service.login_discord_async(dto, response["id"]) - return jsonify(result.to_dict()) + try: + result = await self._auth_service.login_discord_async(dto, response["id"]) + return jsonify(result.to_dict()) + except ServiceException as e: + r = jsonify({"email": dto.email}) + r.status_code = 403 + return r diff --git a/bot/src/bot_api/service/auth_service.py b/bot/src/bot_api/service/auth_service.py index 94410b52..a38fb903 100644 --- a/bot/src/bot_api/service/auth_service.py +++ b/bot/src/bot_api/service/auth_service.py @@ -1,6 +1,5 @@ import hashlib import re -import textwrap import uuid from datetime import datetime, timedelta, timezone from threading import Thread @@ -172,11 +171,7 @@ class AuthService(AuthServiceABC): mail.add_header("Content-Transfer-Encoding: quoted-printable") mail.add_receiver(str(email)) mail.subject = subject - mail.body = textwrap.dedent( - f"""{message} - {self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)} - """ - ) + mail.body = f"{message}\r\n{self._t.transform('api.mail.automatic_mail').format(self._environment.application_name, self._environment.environment_name, self._environment.host_name)}" thr = Thread(target=self._mailer.send_mail, args=[mail]) thr.start() @@ -599,3 +594,12 @@ class AuthService(AuthServiceABC): user.forgot_password_id = None self._auth_users.update_auth_user(user) self._db.save_changes() + + async def resend_confirmation_email_by_mail(self, mail: str): + user = self._auth_users.find_auth_user_by_email(mail) + if user is None: + raise ServiceException(ServiceErrorCode.InvalidUser, f"User not found") + if user.confirmation_id is None: + raise ServiceException(ServiceErrorCode.DataAlreadyExists, f"User already confirmed") + + self._send_confirmation_id_to_user(user) diff --git a/web/src/app/modules/auth/components/login/login.component.ts b/web/src/app/modules/auth/components/login/login.component.ts index 6244a373..be1c51ba 100644 --- a/web/src/app/modules/auth/components/login/login.component.ts +++ b/web/src/app/modules/auth/components/login/login.component.ts @@ -69,6 +69,17 @@ export class LoginComponent implements OnInit { this.spinnerService.hideSpinner(); } + openConfirmationMailInfo(email: string) { + this.confirmDialog.confirmDialog( + this.translate.instant( + "auth.login.message.confirm_email"), + this.translate.instant( + "auth.login.message.confirm_email_d", + { email: email } + ) + ); + } + checkDiscordLogin() { this.route.queryParams.pipe(catchError(err => { this.spinnerService.hideSpinner(); @@ -87,19 +98,31 @@ export class LoginComponent implements OnInit { this.spinnerService.hideSpinner(); this.router.navigate(["auth", "login"]).then(() => { }); - this.state = ""; - this.code = ""; + this.confirmDialog.confirmDialog( + this.translate.instant( + "auth.login.message.confirm_email"), + this.translate.instant( + "auth.login.message.confirm_email_resend" + ), + () => { + this.authService.resendConfirmationMailByMail(err.error.email).subscribe(mail => { + this.openConfirmationMailInfo(err.error.email); + } + ); + + this.state = ""; + this.code = ""; + }, + () => { + this.state = ""; + this.code = ""; + } + ); + return throwError(() => err); })).subscribe(token => { if (token.firstLogin) { - this.confirmDialog.confirmDialog( - this.translate.instant( - "auth.login.message.confirm_email"), - this.translate.instant( - "auth.login.message.confirm_email_d", - { email: this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken(token)) } - ) - ); + this.openConfirmationMailInfo(this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken(token)) ?? ""); } this.authService.saveToken(token); diff --git a/web/src/app/services/auth/auth.service.ts b/web/src/app/services/auth/auth.service.ts index f51db323..58db32e7 100644 --- a/web/src/app/services/auth/auth.service.ts +++ b/web/src/app/services/auth/auth.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { Router } from "@angular/router"; import { JwtHelperService } from "@auth0/angular-jwt"; -import { BehaviorSubject, firstValueFrom, Observable, Subject, Subscription, throwError } from "rxjs"; +import { BehaviorSubject, firstValueFrom, Observable, Subscription, throwError } from "rxjs"; import { catchError } from "rxjs/operators"; import { AdminUpdateUserDTO } from "src/app/models/auth/admin-update-user.dto"; import { AuthRoles } from "src/app/models/auth/auth-roles.enum"; @@ -16,7 +16,6 @@ import { GetFilteredAuthUsersResultDTO } from "src/app/models/selection/auth-use import { SettingsService } from "../settings/settings.service"; import { SpinnerService } from "../spinner/spinner.service"; import { DiscordAuthURL } from "../../models/auth/discord-auth-url.dto"; -import { OAuthDTO } from "../../models/auth/oauth.dto"; @Injectable({ providedIn: "root" @@ -108,6 +107,14 @@ export class AuthService { }); } + resendConfirmationMailByMail(email: string): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/resend-confirmation-email-by-mail/${email}`, { + headers: new HttpHeaders({ + "Content-Type": "application/json" + }) + }); + } + getEMailFromforgotPasswordId(id: string): Observable { return this.http.post(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password/${id}`, { headers: new HttpHeaders({ @@ -173,23 +180,6 @@ export class AuthService { }); } - // /api/auth/discord/register?code= - discordRegister(oAuthDTO: OAuthDTO) { - return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, { - headers: new HttpHeaders({ - "Content-Type": "application/json" - }) - }); - } - - // discordGetUser(code: string, state: string) { - // return this.http.get(`${this.appsettings.getApiURL()}/api/auth/discord/get-user?code=${code}&state=${state}`, { - // headers: new HttpHeaders({ - // 'Content-Type': 'application/json' - // }) - // }); - // } - /* utils */ saveToken(token: TokenDTO): void { localStorage.setItem("jwt", token.token); diff --git a/web/src/assets/i18n/de.json b/web/src/assets/i18n/de.json index 7dcfcf2c..fd0be6ab 100644 --- a/web/src/assets/i18n/de.json +++ b/web/src/assets/i18n/de.json @@ -93,7 +93,8 @@ "login_with_discord": "Mit Discord einloggen", "message": { "confirm_email": "E-Mail Bestätigen", - "confirm_email_d": "Sie müssen die E-Mail {{email}} Bestätigen, in dem Sie den Link öffnen, welchen wir Ihnen zugesendet haben." + "confirm_email_d": "Sie müssen die E-Mail {{email}} Bestätigen, in dem Sie den Link öffnen, welchen wir Ihnen zugesendet haben.", + "confirm_email_resend": "Sollen wir die Bestätigungsmail neu verschicken?" }, "password": "Passwort", "password_required": "Passwort benötigt", diff --git a/web/src/assets/i18n/en.json b/web/src/assets/i18n/en.json index 4ded8551..d8523901 100644 --- a/web/src/assets/i18n/en.json +++ b/web/src/assets/i18n/en.json @@ -93,7 +93,8 @@ "login_with_discord": "Login with discord", "message": { "confirm_email": "Confirm E-Mail", - "confirm_email_d": "You have to confirm your email {{email}} Please confirm your account through the link in the email." + "confirm_email_d": "You have to confirm your email {{email}} Please confirm your account through the link in the email.", + "confirm_email_resend": "Should we resend the confirmation email?" }, "password": "Password", "password_required": "Passwort required",