Compare commits

...

3 Commits

Author SHA1 Message Date
60d81ce18b Resend confirmation mail
Some checks failed
Deploy staging on push / pre-build (push) Successful in 1s
Deploy staging on push / build-bot (push) Failing after 22s
Deploy staging on push / build-web (push) Failing after 21s
Deploy staging on push / deploy (push) Has been skipped
2024-01-26 15:32:01 +01:00
a24fefd3e2 Fixed test mail & delete auth user 2024-01-26 14:03:47 +01:00
8cd5a0d040 Fixed mail 2024-01-26 12:41:26 +01:00
12 changed files with 88 additions and 44 deletions

View File

@ -2,22 +2,22 @@
"api": { "api": {
"api": { "api": {
"test_mail": { "test_mail": {
"message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\nGesendet von {}-{}", "message": "Dies ist eine Test-Mail vom Krümelmonster Web Interface\r\nGesendet von {}-{}",
"subject": "Krümelmonster Web Interface Test-Mail" "subject": "Krümelmonster Web Interface Test-Mail"
} }
}, },
"auth": { "auth": {
"confirmation": { "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" "subject": "E-Mail für {} {} bestätigen"
}, },
"forgot_password": { "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" "subject": "Passwort für {} {} zurücksetzen"
} }
}, },
"mail": { "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": { "common": {

View File

@ -114,3 +114,7 @@ class AuthServiceABC(ABC):
@abstractmethod @abstractmethod
async def reset_password_async(self, rp_dto: ResetPasswordDTO): async def reset_password_async(self, rp_dto: ResetPasswordDTO):
pass pass
@abstractmethod
async def resend_confirmation_email_by_mail(self, mail: str):
pass

@ -1 +1 @@
Subproject commit 521951b8abb0f784b59b6d3e0210606fa193e60a Subproject commit 688e99ae2a075f2db47d05050856661462cf0f09

View File

@ -84,6 +84,11 @@ class AuthController:
self._auth_service.add_auth_user(dto) self._auth_service.add_auth_user(dto)
return "", 200 return "", 200
@Route.post(f"{BasePath}/resend-confirmation-email-by-mail/<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/<id>") @Route.post(f"{BasePath}/register-by-id/<id>")
async def register_id(self, id: str): async def register_id(self, id: str):
result = await self._auth_service.confirm_email_async(id) result = await self._auth_service.confirm_email_async(id)

View File

@ -16,6 +16,7 @@ from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import ( from bot_api.configuration.discord_authentication_settings import (
DiscordAuthenticationSettings, DiscordAuthenticationSettings,
) )
from bot_api.exception.service_exception import ServiceException
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.route.route import Route from bot_api.route.route import Route
@ -90,5 +91,10 @@ class AuthDiscordController:
AuthRoleEnum.normal, AuthRoleEnum.normal,
) )
result = await self._auth_service.login_discord_async(dto, response["id"]) try:
return jsonify(result.to_dict()) 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

View File

@ -1,6 +1,5 @@
import hashlib import hashlib
import re import re
import textwrap
import uuid import uuid
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from threading import Thread from threading import Thread
@ -172,11 +171,7 @@ class AuthService(AuthServiceABC):
mail.add_header("Content-Transfer-Encoding: quoted-printable") mail.add_header("Content-Transfer-Encoding: quoted-printable")
mail.add_receiver(str(email)) mail.add_receiver(str(email))
mail.subject = subject mail.subject = subject
mail.body = textwrap.dedent( 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)}"
f"""{message}
{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 = Thread(target=self._mailer.send_mail, args=[mail])
thr.start() thr.start()
@ -599,3 +594,12 @@ class AuthService(AuthServiceABC):
user.forgot_password_id = None user.forgot_password_id = None
self._auth_users.update_auth_user(user) self._auth_users.update_auth_user(user)
self._db.save_changes() 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)

View File

@ -258,6 +258,15 @@ class AuthUser(TableABC):
""" """
) )
@property
def delete_relations_string(self) -> str:
return str(
f"""
DELETE FROM `AuthUserUsersRelations`
WHERE `AuthUserId` = {self._auth_user_id};
"""
)
@property @property
def delete_string(self) -> str: def delete_string(self) -> str:
return str( return str(

View File

@ -164,6 +164,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC):
def delete_auth_user(self, user: AuthUser): def delete_auth_user(self, user: AuthUser):
self._logger.trace(__name__, f"Send SQL command: {user.delete_string}") self._logger.trace(__name__, f"Send SQL command: {user.delete_string}")
self._context.cursor.execute(user.delete_relations_string)
self._context.cursor.execute(user.delete_string) self._context.cursor.execute(user.delete_string)
def add_auth_user_user_rel(self, rel: AuthUserUsersRelation): def add_auth_user_user_rel(self, rel: AuthUserUsersRelation):

View File

@ -69,6 +69,17 @@ export class LoginComponent implements OnInit {
this.spinnerService.hideSpinner(); 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() { checkDiscordLogin() {
this.route.queryParams.pipe(catchError(err => { this.route.queryParams.pipe(catchError(err => {
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
@ -87,19 +98,31 @@ export class LoginComponent implements OnInit {
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
this.router.navigate(["auth", "login"]).then(() => { this.router.navigate(["auth", "login"]).then(() => {
}); });
this.state = ""; this.confirmDialog.confirmDialog(
this.code = ""; 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); return throwError(() => err);
})).subscribe(token => { })).subscribe(token => {
if (token.firstLogin) { if (token.firstLogin) {
this.confirmDialog.confirmDialog( this.openConfirmationMailInfo(this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken(token)) ?? "");
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.authService.saveToken(token); this.authService.saveToken(token);

View File

@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { JwtHelperService } from "@auth0/angular-jwt"; 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 { catchError } from "rxjs/operators";
import { AdminUpdateUserDTO } from "src/app/models/auth/admin-update-user.dto"; import { AdminUpdateUserDTO } from "src/app/models/auth/admin-update-user.dto";
import { AuthRoles } from "src/app/models/auth/auth-roles.enum"; 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 { SettingsService } from "../settings/settings.service";
import { SpinnerService } from "../spinner/spinner.service"; import { SpinnerService } from "../spinner/spinner.service";
import { DiscordAuthURL } from "../../models/auth/discord-auth-url.dto"; import { DiscordAuthURL } from "../../models/auth/discord-auth-url.dto";
import { OAuthDTO } from "../../models/auth/oauth.dto";
@Injectable({ @Injectable({
providedIn: "root" providedIn: "root"
@ -108,6 +107,14 @@ export class AuthService {
}); });
} }
resendConfirmationMailByMail(email: string): Observable<unknown> {
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<EMailStringDTO> { getEMailFromforgotPasswordId(id: string): Observable<EMailStringDTO> {
return this.http.post<EMailStringDTO>(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password/${id}`, { return this.http.post<EMailStringDTO>(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password/${id}`, {
headers: new HttpHeaders({ 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<AuthUserDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/get-user?code=${code}&state=${state}`, {
// headers: new HttpHeaders({
// 'Content-Type': 'application/json'
// })
// });
// }
/* utils */ /* utils */
saveToken(token: TokenDTO): void { saveToken(token: TokenDTO): void {
localStorage.setItem("jwt", token.token); localStorage.setItem("jwt", token.token);

View File

@ -93,7 +93,8 @@
"login_with_discord": "Mit Discord einloggen", "login_with_discord": "Mit Discord einloggen",
"message": { "message": {
"confirm_email": "E-Mail Bestätigen", "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": "Passwort",
"password_required": "Passwort benötigt", "password_required": "Passwort benötigt",

View File

@ -93,7 +93,8 @@
"login_with_discord": "Login with discord", "login_with_discord": "Login with discord",
"message": { "message": {
"confirm_email": "Confirm E-Mail", "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": "Password",
"password_required": "Passwort required", "password_required": "Passwort required",