forked from sh-edraft.de/sh_discord_bot
		
	Added logic to register by discord #70
This commit is contained in:
		| @@ -7,6 +7,7 @@ from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria | ||||
| from bot_api.model.auth_user_dto import AuthUserDTO | ||||
| from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO | ||||
| from bot_api.model.email_string_dto import EMailStringDTO | ||||
| from bot_api.model.o_auth_dto import OAuthDTO | ||||
| from bot_api.model.reset_password_dto import ResetPasswordDTO | ||||
| from bot_api.model.token_dto import TokenDTO | ||||
| from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO | ||||
| @@ -37,7 +38,7 @@ class AuthServiceABC(ABC): | ||||
|     async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass | ||||
|     async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass | ||||
| @@ -46,7 +47,10 @@ class AuthServiceABC(ABC): | ||||
|     async def add_auth_user_async(self, user_dto: AuthUserDTO): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO): pass | ||||
|     async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO) -> OAuthDTO: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass | ||||
|   | ||||
| @@ -13,7 +13,8 @@ | ||||
|   }, | ||||
|   "DiscordAuthentication": { | ||||
|     "ClientSecret": "V3FTb3JYVFBiVktEeHZxdWJDWW4xcnBCbXRwdmpwcy0=", | ||||
|     "RedirectURL": "http://localhost:5000/api/auth/discord/register", | ||||
|     "_RedirectURL": "http://localhost:5000/api/auth/discord/register", | ||||
|     "RedirectURL": "http://localhost:4200/auth/register", | ||||
|     "Scope": [ | ||||
|       "identify", | ||||
|       "email" | ||||
|   | ||||
| @@ -7,15 +7,17 @@ from cpl_core.mailing import EMailClientABC, EMailClientSettings | ||||
| from cpl_core.utils import CredentialManager | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| from cpl_translation import TranslatePipe | ||||
| from flask import jsonify | ||||
| from flask import jsonify, Response | ||||
| from flask import request, session | ||||
| from requests_oauthlib import OAuth2Session | ||||
|  | ||||
| from bot_api.abc.auth_service_abc import AuthServiceABC | ||||
| from bot_api.api import Api | ||||
| from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings | ||||
| from bot_api.json_processor import JSONProcessor | ||||
| from bot_api.logging.api_logger import ApiLogger | ||||
| from bot_api.model.auth_user_dto import AuthUserDTO | ||||
| from bot_api.model.o_auth_dto import OAuthDTO | ||||
| from bot_api.route.route import Route | ||||
| from bot_data.model.auth_role_enum import AuthRoleEnum | ||||
|  | ||||
| @@ -50,27 +52,26 @@ class AuthDiscordController: | ||||
|         self._mailer = mailer | ||||
|         self._auth_service = auth_service | ||||
|  | ||||
|     @Route.get(f'{BasePath}/get-url') | ||||
|     async def get_url(self): | ||||
|         oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope) | ||||
|         login_url, state = oauth.authorization_url(self._auth_settings.auth_url) | ||||
|         session['state'] = state | ||||
|         # return jsonify({'loginURL': login_url}) | ||||
|         return '<a href="' + login_url + '">Login with Discord</a>' | ||||
|  | ||||
|     @Route.get(f'{BasePath}/register') | ||||
|     async def discord_register(self): | ||||
|         discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=session['state'], scope=self._auth_settings.scope) | ||||
|     def _get_user_from_discord_response(self) -> dict: | ||||
|         discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope) | ||||
|         token = discord.fetch_token( | ||||
|             self._auth_settings.token_url, | ||||
|             client_secret=CredentialManager.decrypt(self._auth_settings.client_secret), | ||||
|             authorization_response=request.url, | ||||
|         ) | ||||
|         session['discord_token'] = token | ||||
|         discord = OAuth2Session(self._bot.user.id, token=token) | ||||
|         response = discord.get('https://discordapp.com/api' + '/users/@me').json() | ||||
|         return discord.get('https://discordapp.com/api' + '/users/@me').json() | ||||
|  | ||||
|         await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO( | ||||
|     @Route.get(f'{BasePath}/get-url') | ||||
|     async def get_url(self): | ||||
|         oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope) | ||||
|         login_url, state = oauth.authorization_url(self._auth_settings.auth_url) | ||||
|         return jsonify({'loginUrl': login_url}) | ||||
|  | ||||
|     @Route.get(f'{BasePath}/create-user') | ||||
|     async def discord_create_user(self) -> Response: | ||||
|         response = self._get_user_from_discord_response() | ||||
|         result = await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO( | ||||
|             0, | ||||
|             response['username'], | ||||
|             response['discriminator'], | ||||
| @@ -80,4 +81,10 @@ class AuthDiscordController: | ||||
|             AuthRoleEnum.normal, | ||||
|             response['id'] | ||||
|         )) | ||||
|         return jsonify(result.to_dict()) | ||||
|  | ||||
|     @Route.post(f'{BasePath}/register') | ||||
|     async def discord_register(self): | ||||
|         dto: OAuthDTO = JSONProcessor.process(OAuthDTO, request.get_json(force=True, silent=True)) | ||||
|         await self._auth_service.add_auth_user_by_oauth_async(dto) | ||||
|         return '', 200 | ||||
|   | ||||
| @@ -8,14 +8,14 @@ class AuthUserDTO(DtoABC): | ||||
|  | ||||
|     def __init__( | ||||
|             self, | ||||
|             id: int, | ||||
|             first_name: str, | ||||
|             last_name: str, | ||||
|             email: str, | ||||
|             password: str, | ||||
|             confirmation_id: Optional[str], | ||||
|             auth_role: AuthRoleEnum, | ||||
|             user_id: Optional[int], | ||||
|             id: int = None, | ||||
|             first_name: str = None, | ||||
|             last_name: str = None, | ||||
|             email: str = None, | ||||
|             password: str = None, | ||||
|             confirmation_id: Optional[str] = None, | ||||
|             auth_role: AuthRoleEnum = None, | ||||
|             user_id: Optional[int] = None, | ||||
|     ): | ||||
|         DtoABC.__init__(self) | ||||
|  | ||||
| @@ -27,7 +27,7 @@ class AuthUserDTO(DtoABC): | ||||
|         self._is_confirmed = confirmation_id is None | ||||
|         self._auth_role = auth_role | ||||
|         self._user_id = user_id | ||||
|          | ||||
|  | ||||
|     @property | ||||
|     def id(self) -> int: | ||||
|         return self._id | ||||
|   | ||||
							
								
								
									
										44
									
								
								kdb-bot/src/bot_api/model/o_auth_dto.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								kdb-bot/src/bot_api/model/o_auth_dto.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| from typing import Optional | ||||
|  | ||||
| from bot_api.abc.dto_abc import DtoABC | ||||
| from bot_api.model.auth_user_dto import AuthUserDTO | ||||
| from bot_data.model.auth_role_enum import AuthRoleEnum | ||||
|  | ||||
|  | ||||
| class OAuthDTO(DtoABC): | ||||
|  | ||||
|     def __init__( | ||||
|             self, | ||||
|             user: AuthUserDTO, | ||||
|             o_auth_id: Optional[str], | ||||
|     ): | ||||
|         DtoABC.__init__(self) | ||||
|  | ||||
|         self._user = user | ||||
|         self._oauth_id = o_auth_id | ||||
|  | ||||
|     @property | ||||
|     def user(self) -> AuthUserDTO: | ||||
|         return self._user | ||||
|  | ||||
|     @user.setter | ||||
|     def user(self, value: AuthUserDTO): | ||||
|         self._user = value | ||||
|  | ||||
|     @property | ||||
|     def oauth_id(self) -> Optional[str]: | ||||
|         return self._oauth_id | ||||
|  | ||||
|     @oauth_id.setter | ||||
|     def oauth_id(self, value: Optional[str]): | ||||
|         self._oauth_id = value | ||||
|  | ||||
|     def from_dict(self, values: dict): | ||||
|         self._user = AuthUserDTO().from_dict(values['user']) | ||||
|         self._oauth_id = values['oAuthId'] | ||||
|  | ||||
|     def to_dict(self) -> dict: | ||||
|         return { | ||||
|             'user': self._user.to_dict(), | ||||
|             'oAuthId': self._oauth_id | ||||
|         } | ||||
| @@ -25,6 +25,7 @@ from bot_api.mail.mail_thread import MailThread | ||||
| from bot_api.model.auth_user_dto import AuthUserDTO | ||||
| from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO | ||||
| from bot_api.model.email_string_dto import EMailStringDTO | ||||
| from bot_api.model.o_auth_dto import OAuthDTO | ||||
| from bot_api.model.reset_password_dto import ResetPasswordDTO | ||||
| from bot_api.model.token_dto import TokenDTO | ||||
| from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO | ||||
| @@ -190,9 +191,10 @@ class AuthService(AuthServiceABC): | ||||
|             users.total_count | ||||
|         ) | ||||
|  | ||||
|     async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO: | ||||
|     async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: | ||||
|         try: | ||||
|             return AUT.to_dto(self._auth_users.get_auth_user_by_email(email)) | ||||
|             user = self._auth_users.get_auth_user_by_email(email) | ||||
|             return AUT.to_dto(user, password=user.password if with_password else None) | ||||
|         except Exception as e: | ||||
|             self._logger.error(__name__, f'AuthUser not found', e) | ||||
|             raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}') | ||||
| @@ -225,24 +227,54 @@ class AuthService(AuthServiceABC): | ||||
|             self._logger.error(__name__, f'Cannot add user with E-Mal {user_dto.email}', e) | ||||
|             raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail") | ||||
|  | ||||
|     async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO): | ||||
|     async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): | ||||
|         db_user = self._auth_users.find_auth_user_by_email(dto.user.email) | ||||
|  | ||||
|         if db_user is None: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') | ||||
|  | ||||
|         if db_user.oauth_id != dto.oauth_id: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong OAuthId') | ||||
|  | ||||
|         db_user.first_name = dto.user.first_name | ||||
|         db_user.last_name = dto.user.last_name | ||||
|         db_user.password_salt = uuid.uuid4() | ||||
|         db_user.password = self._hash_sha256(dto.user.password, db_user.password_salt) | ||||
|         db_user.oauth_id = None | ||||
|         self._auth_users.update_auth_user(db_user) | ||||
|         self._db.save_changes() | ||||
|  | ||||
|     async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO) -> OAuthDTO: | ||||
|         db_user = self._auth_users.find_auth_user_by_email(user_dto.email) | ||||
|         # user exists | ||||
|         if db_user is not None and db_user.user_id is not None: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') | ||||
|             # raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') | ||||
|             self._logger.debug(__name__, f'Discord user already exists') | ||||
|             return OAuthDTO(AUT.to_dto(db_user), None) | ||||
|  | ||||
|         # user exists but discord user id not set | ||||
|         elif db_user is not None and db_user.user_id is None: | ||||
|             self._logger.debug(__name__, f'Auth user exists but not linked with discord') | ||||
|             user = self._users.get_users_by_discord_id(user_dto.user_id).single() | ||||
|             db_user.user_id = user.user_id | ||||
|             self._auth_users.update_auth_user(db_user) | ||||
|             self._db.save_changes() | ||||
|             return AUT.to_dto(db_user) | ||||
|             db_user.oauth_id = None | ||||
|  | ||||
|         # user does not exists | ||||
|         await self.add_auth_user_async(user_dto) | ||||
|         db_user = self._auth_users.get_auth_user_by_email(user_dto.email) | ||||
|         return AUT.to_dto(db_user, password=db_user.password) | ||||
|         else: | ||||
|             # user does not exists | ||||
|             self._logger.debug(__name__, f'Auth user does not exist') | ||||
|             try: | ||||
|                 user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id | ||||
|             except Exception as e: | ||||
|                 self._logger.error(__name__, f'User not found') | ||||
|                 user_dto.user_id = None | ||||
|  | ||||
|             await self.add_auth_user_async(user_dto) | ||||
|             db_user = self._auth_users.get_auth_user_by_email(user_dto.email) | ||||
|             db_user.oauth_id = uuid.uuid4() | ||||
|  | ||||
|         self._auth_users.update_auth_user(db_user) | ||||
|         self._db.save_changes() | ||||
|         return OAuthDTO(AUT.to_dto(db_user), db_user.oauth_id) | ||||
|  | ||||
|     async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): | ||||
|         if update_user_dto is None: | ||||
|   | ||||
| @@ -19,6 +19,7 @@ class AuthUserTransformer(TransformerABC): | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|             datetime.now(tz=timezone.utc), | ||||
|             AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), | ||||
|             dto.user_id, | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class ApiMigration(MigrationABC): | ||||
|               `RefreshToken` VARCHAR(255), | ||||
|               `ConfirmationId` VARCHAR(255) DEFAULT NULL, | ||||
|               `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, | ||||
|               `OAuthId` VARCHAR(255) DEFAULT NULL, | ||||
|               `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, | ||||
|               `AuthRole` INT NOT NULL DEFAULT '0', | ||||
|               `UserId` BIGINT DEFAULT NULL, | ||||
|   | ||||
| @@ -19,6 +19,7 @@ class AuthUser(TableABC): | ||||
|             refresh_token: Optional[str], | ||||
|             confirmation_id: Optional[str], | ||||
|             forgot_password_id: Optional[str], | ||||
|             oauth_id: Optional[str], | ||||
|             refresh_token_expire_time: datetime, | ||||
|             auth_role: AuthRoleEnum, | ||||
|             user_id: Optional[int], | ||||
| @@ -34,6 +35,7 @@ class AuthUser(TableABC): | ||||
|         self._password_salt = uuid.uuid4() if password_salt is None else password_salt | ||||
|         self._refresh_token = refresh_token | ||||
|         self._confirmation_id = confirmation_id | ||||
|         self._oauth_id = oauth_id | ||||
|         self._forgot_password_id = forgot_password_id | ||||
|         self._refresh_token_expire_time = refresh_token_expire_time | ||||
|  | ||||
| @@ -95,23 +97,31 @@ class AuthUser(TableABC): | ||||
|     @refresh_token.setter | ||||
|     def refresh_token(self, value: Optional[str]): | ||||
|         self._refresh_token = value | ||||
|          | ||||
|  | ||||
|     @property | ||||
|     def confirmation_id(self) -> Optional[str]: | ||||
|         return self._confirmation_id | ||||
|      | ||||
|  | ||||
|     @confirmation_id.setter | ||||
|     def confirmation_id(self, value: Optional[str]): | ||||
|         self._confirmation_id = value | ||||
|          | ||||
|  | ||||
|     @property | ||||
|     def forgot_password_id(self) -> Optional[str]: | ||||
|         return self._forgot_password_id | ||||
|      | ||||
|  | ||||
|     @forgot_password_id.setter | ||||
|     def forgot_password_id(self, value: Optional[str]): | ||||
|         self._forgot_password_id = value | ||||
|  | ||||
|     @property | ||||
|     def oauth_id(self) -> Optional[str]: | ||||
|         return self._oauth_id | ||||
|  | ||||
|     @oauth_id.setter | ||||
|     def oauth_id(self, value: Optional[str]): | ||||
|         self._oauth_id = value | ||||
|  | ||||
|     @property | ||||
|     def refresh_token_expire_time(self) -> datetime: | ||||
|         return self._refresh_token_expire_time | ||||
| @@ -183,6 +193,7 @@ class AuthUser(TableABC): | ||||
|                 `RefreshToken`, | ||||
|                 `ConfirmationId`, | ||||
|                 `ForgotPasswordId`, | ||||
|                 `OAuthId`, | ||||
|                 `RefreshTokenExpiryTime`, | ||||
|                 `AuthRole`, | ||||
|                 `UserId`, | ||||
| @@ -198,6 +209,7 @@ class AuthUser(TableABC): | ||||
|                     '{"NULL" if self._refresh_token is None else self._refresh_token}', | ||||
|                     '{"NULL" if self._confirmation_id is None else self._confirmation_id}', | ||||
|                     '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', | ||||
|                     '{"NULL" if self._oauth_id is None else self._oauth_id}', | ||||
|                     '{self._refresh_token_expire_time}', | ||||
|                     {self._auth_role_id.value}, | ||||
|                     {"NULL" if self._user_id is None else self._user_id}, | ||||
| @@ -218,6 +230,7 @@ class AuthUser(TableABC): | ||||
|             `RefreshToken` = '{self._refresh_token}',  | ||||
|             `ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}',  | ||||
|             `ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', | ||||
|             `OAuthId` = '{"NULL" if self._oauth_id is None else self._oauth_id}', | ||||
|             `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', | ||||
|             `AuthRole` = {self._auth_role_id.value}, | ||||
|             `UserId` = {"NULL" if self._user_id is None else self._user_id}, | ||||
|   | ||||
| @@ -37,8 +37,9 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): | ||||
|             self._get_value_from_result(result[7]), | ||||
|             self._get_value_from_result(result[8]), | ||||
|             self._get_value_from_result(result[9]), | ||||
|             AuthRoleEnum(self._get_value_from_result(result[10])), | ||||
|             self._get_value_from_result(result[11]), | ||||
|             self._get_value_from_result(result[10]), | ||||
|             AuthRoleEnum(self._get_value_from_result(result[11])), | ||||
|             self._get_value_from_result(result[12]), | ||||
|             id=self._get_value_from_result(result[0]) | ||||
|         ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								kdb-web/src/app/models/auth/discord-auth-url.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								kdb-web/src/app/models/auth/discord-auth-url.dto.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| export interface DiscordAuthURL { | ||||
|   loginUrl: string; | ||||
| } | ||||
							
								
								
									
										6
									
								
								kdb-web/src/app/models/auth/oauth.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								kdb-web/src/app/models/auth/oauth.dto.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import { AuthUserDTO } from "./auth-user.dto"; | ||||
|  | ||||
| export interface OAuthDTO { | ||||
|   user: AuthUserDTO; | ||||
|     oAuthId: string; | ||||
| } | ||||
| @@ -1,85 +1,91 @@ | ||||
| <section class="login-wrapper"> | ||||
|     <div class="login-form-wrapper register-form-wrapper"> | ||||
|         <div class="login-form"> | ||||
|             <form [formGroup]="loginForm"> | ||||
|                 <h1>sh-edraft.de</h1> | ||||
|                 <div class="input-field"> | ||||
|                     <input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}" | ||||
|                         autocomplete="given-name"> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div | ||||
|                             *ngIf="loginForm.controls.firstName.errors && loginForm.controls.firstName.errors['required'] || authUserAtrErrors.firstName.required"> | ||||
|                             {{'auth.register.first_name_required' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.firstName.wrongData">{{'auth.register.first_name_invalid' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="input-field"> | ||||
|                     <input type="text" pInputText formControlName="lastName" placeholder="{{'auth.register.last_name' | translate}}" | ||||
|                         autocomplete="family-name"> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div | ||||
|                             *ngIf="loginForm.controls.lastName.errors && loginForm.controls.lastName.errors['required'] || authUserAtrErrors.lastName.required"> | ||||
|                             {{'auth.register.last_name_required' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.lastName.wrongData">{{'auth.register.last_name_invalid' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="input-field"> | ||||
|                     <input type="email" pInputText formControlName="email" placeholder="{{'auth.register.e_mail' | translate}}" | ||||
|                         [ngClass]="{ 'invalid-feedback-input': submitted && (authUserAtrErrors.email.wrongData || loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required)}" | ||||
|                         autocomplete="username email"> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div | ||||
|                             *ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required"> | ||||
|                             {{'auth.register.e_mail_required' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.register.user_already_exists' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="input-field"> | ||||
|                     <input type="email" pInputText formControlName="emailRepeat" placeholder="{{'auth.register.repeat_e_mail' | translate}}" | ||||
|                         [ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.email}"> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div *ngIf="repeatErrors.email">{{'auth.register.e_mails_not_match' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="input-field"> | ||||
|                     <p-password type="password" formControlName="password" placeholder="{{'auth.register.password' | translate}}" | ||||
|                         ngClass="{ 'invalid-feedback': submitted && loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required}" | ||||
|                         autocomplete="new-password" [toggleMask]="true" [feedback]="false" | ||||
|                         styleClass="p-password p-component p-inputwrapper p-input-icon-right"></p-password> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div | ||||
|                             *ngIf="loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required"> | ||||
|                             {{'auth.register.password_required' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="input-field"> | ||||
|                     <p-password type="password" formControlName="passwordRepeat" placeholder="{{'auth.register.repeat_password' | translate}}" | ||||
|                         [ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.password}" [toggleMask]="true" | ||||
|                         [feedback]="false" styleClass="p-password p-component p-inputwrapper p-input-icon-right"> | ||||
|                     </p-password> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div *ngIf="repeatErrors.password">{{'auth.register.passwords_not_match' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="login-form-submit"> | ||||
|                     <button pButton label="{{'auth.register.register' | translate}}" class="btn login-form-submit-btn" (click)="register()" | ||||
|                         [disabled]="loginForm.invalid"></button> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="login-form-sub-button-wrapper"> | ||||
|                     <div class="login-form-sub-btn-wrapper"> | ||||
|                         <button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </form> | ||||
|   <div class="login-form-wrapper register-form-wrapper"> | ||||
|     <div class="login-form"> | ||||
|       <form [formGroup]="loginForm"> | ||||
|         <h1>sh-edraft.de</h1> | ||||
|         <div class="input-field"> | ||||
|           <input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}" | ||||
|                  autocomplete="given-name"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
|               *ngIf="loginForm.controls.firstName.errors && loginForm.controls.firstName.errors['required'] || authUserAtrErrors.firstName.required"> | ||||
|               {{'auth.register.first_name_required' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.firstName.wrongData">{{'auth.register.first_name_invalid' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <app-auth-header></app-auth-header> | ||||
| </section> | ||||
|         <div class="input-field"> | ||||
|           <input type="text" pInputText formControlName="lastName" placeholder="{{'auth.register.last_name' | translate}}" | ||||
|                  autocomplete="family-name"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
|               *ngIf="loginForm.controls.lastName.errors && loginForm.controls.lastName.errors['required'] || authUserAtrErrors.lastName.required"> | ||||
|               {{'auth.register.last_name_required' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.lastName.wrongData">{{'auth.register.last_name_invalid' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="input-field"> | ||||
|           <input type="email" pInputText formControlName="email" placeholder="{{'auth.register.e_mail' | translate}}" | ||||
|                  [ngClass]="{ 'invalid-feedback-input': submitted && (authUserAtrErrors.email.wrongData || loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required)}" | ||||
|                  autocomplete="username email"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
|               *ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required"> | ||||
|               {{'auth.register.e_mail_required' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.register.user_already_exists' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="input-field"> | ||||
|           <input type="email" pInputText formControlName="emailRepeat" placeholder="{{'auth.register.repeat_e_mail' | translate}}" | ||||
|                  [ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.email}"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div *ngIf="repeatErrors.email">{{'auth.register.e_mails_not_match' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="input-field"> | ||||
|           <p-password type="password" formControlName="password" placeholder="{{'auth.register.password' | translate}}" | ||||
|                       ngClass="{ 'invalid-feedback': submitted && loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required}" | ||||
|                       autocomplete="new-password" [toggleMask]="true" [feedback]="false" | ||||
|                       styleClass="p-password p-component p-inputwrapper p-input-icon-right"></p-password> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
|               *ngIf="loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required"> | ||||
|               {{'auth.register.password_required' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="input-field"> | ||||
|           <p-password type="password" formControlName="passwordRepeat" placeholder="{{'auth.register.repeat_password' | translate}}" | ||||
|                       [ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.password}" [toggleMask]="true" | ||||
|                       [feedback]="false" styleClass="p-password p-component p-inputwrapper p-input-icon-right"> | ||||
|           </p-password> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div *ngIf="repeatErrors.password">{{'auth.register.passwords_not_match' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="login-form-submit"> | ||||
|           <button pButton label="{{'auth.register.register' | translate}}" class="btn login-form-submit-btn" (click)="register()" | ||||
|                   [disabled]="loginForm.invalid"></button> | ||||
|         </div> | ||||
|  | ||||
|         <div class="login-form-sub-button-wrapper" *ngIf="!code && !state"> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.register.register_with_discord' | translate}}" class="btn login-form-sub-btn" (click)="discordLogin()"></button> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="login-form-sub-button-wrapper"> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </form> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
|   <app-auth-header></app-auth-header> | ||||
| </section> | ||||
|   | ||||
| @@ -1,19 +1,21 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; | ||||
| import { ActivatedRoute, Router } from '@angular/router'; | ||||
| import { catchError } from 'rxjs/operators'; | ||||
| import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; | ||||
| import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; | ||||
| import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; | ||||
| import { ErrorDTO } from 'src/app/models/error/error-dto'; | ||||
| import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; | ||||
| import { AuthService } from 'src/app/services/auth/auth.service'; | ||||
| import { SpinnerService } from 'src/app/services/spinner/spinner.service'; | ||||
| import { Component, OnInit } from "@angular/core"; | ||||
| import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; | ||||
| import { ActivatedRoute, Router } from "@angular/router"; | ||||
| import { catchError, finalize } from "rxjs/operators"; | ||||
| import { AuthErrorMessages } from "src/app/models/auth/auth-error-messages.enum"; | ||||
| import { AuthUserDTO } from "src/app/models/auth/auth-user.dto"; | ||||
| import { AuthUserAtrErrors } from "src/app/models/auth/auth-user-atr-errors"; | ||||
| import { ErrorDTO } from "src/app/models/error/error-dto"; | ||||
| import { ServiceErrorCode } from "src/app/models/error/service-error-code.enum"; | ||||
| import { AuthService } from "src/app/services/auth/auth.service"; | ||||
| import { SpinnerService } from "src/app/services/spinner/spinner.service"; | ||||
| import { throwError } from "rxjs"; | ||||
| import { OAuthDTO } from "../../../../models/auth/oauth.dto"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-registration', | ||||
|   templateUrl: './registration.component.html', | ||||
|   styleUrls: ['./registration.component.scss'] | ||||
|   selector: "app-registration", | ||||
|   templateUrl: "./registration.component.html", | ||||
|   styleUrls: ["./registration.component.scss"] | ||||
| }) | ||||
| export class RegistrationComponent implements OnInit { | ||||
|  | ||||
| @@ -35,6 +37,11 @@ export class RegistrationComponent implements OnInit { | ||||
|   showEMailConfirmation = false; | ||||
|   showEMailConfirmationError = false; | ||||
|  | ||||
|   code!: string; | ||||
|   state!: string; | ||||
|   user!: AuthUserDTO; | ||||
|   oAuthId!: string; | ||||
|  | ||||
|   constructor( | ||||
|     private authService: AuthService, | ||||
|     private formBuilder: FormBuilder, | ||||
| @@ -45,16 +52,64 @@ export class RegistrationComponent implements OnInit { | ||||
|     this.spinnerService.showSpinner(); | ||||
|     this.authService.isUserLoggedInAsync().then(res => { | ||||
|       if (res) { | ||||
|         this.router.navigate(['/dashboard']); | ||||
|         this.router.navigate(["/dashboard"]); | ||||
|       } | ||||
|       this.spinnerService.hideSpinner(); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.initData(); | ||||
|     this.spinnerService.showSpinner(); | ||||
|     this.route.queryParams.pipe(catchError(err => { | ||||
|       this.spinnerService.hideSpinner(); | ||||
|       this.router.navigate(["auth", "login"]).then(() => { | ||||
|       }); | ||||
|       return throwError(() => err); | ||||
|     })).subscribe(params => { | ||||
|         if (!params["code"] || !params["state"]) { | ||||
|           this.spinnerService.hideSpinner(); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         if (this.user) { | ||||
|           this.spinnerService.hideSpinner(); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         this.code = params["code"]; | ||||
|         this.state = params["state"]; | ||||
|         this.authService.discordCreateUser(this.code, this.state).pipe(catchError(err => { | ||||
|           this.spinnerService.hideSpinner(); | ||||
|           this.router.navigate(["auth", "login"]).then(() => { | ||||
|           }); | ||||
|           return throwError(() => err); | ||||
|         })).subscribe(oAuthDTO => { | ||||
|             if (oAuthDTO) { | ||||
|               this.user = oAuthDTO.user; | ||||
|               this.oAuthId = oAuthDTO.oAuthId; | ||||
|             } | ||||
|             if (this.user && !this.oAuthId) { | ||||
|               this.router.navigate(["auth", "login"]).then(() => { | ||||
|               }); | ||||
|               return; | ||||
|             } | ||||
|  | ||||
|             this.router.navigate(["auth", "register"]).then(() => { | ||||
|             }); | ||||
|             this.initData(); | ||||
|           } | ||||
|         ); | ||||
|         this.initData(); | ||||
|       } | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   initData() { | ||||
|     this.initLoginForm(); | ||||
|     this.resetStateFlags(); | ||||
|     this.confirmEMail(); | ||||
|     this.spinnerService.hideSpinner(); | ||||
|   } | ||||
|  | ||||
|   resetStateFlags(): void { | ||||
| @@ -66,18 +121,23 @@ export class RegistrationComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   login(): void { | ||||
|     this.router.navigate(['/auth/login']); | ||||
|     this.router.navigate(["/auth/login"]); | ||||
|   } | ||||
|  | ||||
|   initLoginForm(): void { | ||||
|     this.loginForm = this.formBuilder.group({ | ||||
|       firstName: ['', Validators.required], | ||||
|       lastName: ['', Validators.required], | ||||
|       email: ['', [Validators.required, Validators.email]], | ||||
|       emailRepeat: ['', [Validators.required, Validators.email]], | ||||
|       password: ['', [Validators.required, Validators.minLength(8)]], | ||||
|       passwordRepeat: ['', [Validators.required, Validators.minLength(8)]] | ||||
|       firstName: [this.user ? this.user.firstName : "", Validators.required], | ||||
|       lastName: [this.user ? this.user.lastName : "", Validators.required], | ||||
|       email: [this.user ? this.user.email : "", [Validators.required, Validators.email]], | ||||
|       emailRepeat: [this.user ? this.user.email : "", [Validators.required, Validators.email]], | ||||
|       password: [this.user ? this.user.password : "", [Validators.required, Validators.minLength(8)]], | ||||
|       passwordRepeat: [this.user ? this.user.password : "", [Validators.required, Validators.minLength(8)]] | ||||
|     }); | ||||
|  | ||||
|     if (this.user) { | ||||
|       this.loginForm.controls.email.disable(); | ||||
|       this.loginForm.controls.emailRepeat.disable(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   register(): void { | ||||
| @@ -100,13 +160,49 @@ export class RegistrationComponent implements OnInit { | ||||
|     } | ||||
|  | ||||
|     this.spinnerService.showSpinner(); | ||||
|     if (this.user && this.oAuthId) { | ||||
|       this.registerWithOAuth(); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.registerLocal(); | ||||
|   } | ||||
|  | ||||
|   private registerWithOAuth() { | ||||
|     const oAuthDTO: OAuthDTO = { | ||||
|       user: { | ||||
|         firstName: this.loginForm.value.firstName ?? this.user.firstName, | ||||
|         lastName: this.loginForm.value.lastName ?? this.user.lastName, | ||||
|         email: this.loginForm.value.email ?? this.user.email, | ||||
|         password: this.loginForm.value.password ?? null | ||||
|       }, | ||||
|       oAuthId: this.oAuthId | ||||
|     }; | ||||
|     this.authService.discordRegister(oAuthDTO) | ||||
|       .pipe(catchError(error => { | ||||
|         if (error.error !== null) { | ||||
|           const err: ErrorDTO = error.error; | ||||
|  | ||||
|           if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.UserAlreadyExists) { | ||||
|             this.authUserAtrErrors.email.wrongData = true; | ||||
|           } | ||||
|         } | ||||
|         this.spinnerService.hideSpinner(); | ||||
|         throw error; | ||||
|       })) | ||||
|       .subscribe(resp => { | ||||
|         this.spinnerService.hideSpinner(); | ||||
|         this.router.navigate(["/auth/login"]); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   private registerLocal() { | ||||
|     const user: AuthUserDTO = { | ||||
|       firstName: this.loginForm.value.firstName ?? null, | ||||
|       lastName: this.loginForm.value.lastName ?? null, | ||||
|       email: this.loginForm.value.email ?? null, | ||||
|       password: this.loginForm.value.password ?? null | ||||
|     }; | ||||
|  | ||||
|     this.authService.register(user) | ||||
|       .pipe(catchError(error => { | ||||
|         if (error.error !== null) { | ||||
| @@ -121,24 +217,30 @@ export class RegistrationComponent implements OnInit { | ||||
|       })) | ||||
|       .subscribe(resp => { | ||||
|         this.spinnerService.hideSpinner(); | ||||
|         this.router.navigate(['/auth/login']); | ||||
|         this.router.navigate(["/auth/login"]); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   confirmEMail(): void { | ||||
|     const id = this.route.snapshot.params['id']; | ||||
|     const id = this.route.snapshot.params["id"]; | ||||
|     if (id) { | ||||
|       this.spinnerService.showSpinner(); | ||||
|       this.authService.confirmEMail(id) | ||||
|         .pipe(catchError(error => { | ||||
|           this.router.navigate(['/auth/login']); | ||||
|           this.router.navigate(["/auth/login"]); | ||||
|           this.spinnerService.hideSpinner(); | ||||
|           throw error; | ||||
|         })) | ||||
|         .subscribe(resp => { | ||||
|           this.spinnerService.hideSpinner(); | ||||
|           this.router.navigate(['/auth/login']); | ||||
|           this.router.navigate(["/auth/login"]); | ||||
|         }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   discordLogin() { | ||||
|     this.authService.getDiscordAuthURL().subscribe(url => { | ||||
|       window.location.href = url.loginUrl; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| import { HttpClient, HttpHeaders } from '@angular/common/http'; | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | ||||
| import { JwtHelperService } from '@auth0/angular-jwt'; | ||||
| import { firstValueFrom, Observable, Subject, Subscription } 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'; | ||||
| import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; | ||||
| import { EMailStringDTO } from 'src/app/models/auth/email-string.dto'; | ||||
| import { ResetPasswordDTO } from 'src/app/models/auth/reset-password.dto'; | ||||
| import { TokenDTO } from 'src/app/models/auth/token.dto'; | ||||
| import { UpdateUserDTO } from 'src/app/models/auth/update-user.dto'; | ||||
| import { AuthUserSelectCriterion } from 'src/app/models/selection/auth-user/auth-user-select-criterion.dto'; | ||||
| import { GetFilteredAuthUsersResultDTO } from 'src/app/models/selection/auth-user/get-filtered-auth-users-result.dto'; | ||||
| import { SettingsService } from '../settings/settings.service'; | ||||
| import { SpinnerService } from '../spinner/spinner.service'; | ||||
| import { HttpClient, HttpHeaders } from "@angular/common/http"; | ||||
| import { Injectable } from "@angular/core"; | ||||
| import { Router } from "@angular/router"; | ||||
| import { JwtHelperService } from "@auth0/angular-jwt"; | ||||
| import { firstValueFrom, Observable, Subject, Subscription } 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"; | ||||
| import { AuthUserDTO } from "src/app/models/auth/auth-user.dto"; | ||||
| import { EMailStringDTO } from "src/app/models/auth/email-string.dto"; | ||||
| import { ResetPasswordDTO } from "src/app/models/auth/reset-password.dto"; | ||||
| import { TokenDTO } from "src/app/models/auth/token.dto"; | ||||
| import { UpdateUserDTO } from "src/app/models/auth/update-user.dto"; | ||||
| import { AuthUserSelectCriterion } from "src/app/models/selection/auth-user/auth-user-select-criterion.dto"; | ||||
| import { GetFilteredAuthUsersResultDTO } from "src/app/models/selection/auth-user/get-filtered-auth-users-result.dto"; | ||||
| 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' | ||||
| @@ -157,6 +159,39 @@ export class AuthService { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /* discord auth */ | ||||
|   getDiscordAuthURL() { | ||||
|     return this.http.get<DiscordAuthURL>(`${this.appsettings.getApiURL()}/api/auth/discord/get-url`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         'Content-Type': 'application/json' | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
|   discordCreateUser(code: string, state: string) { | ||||
|     return this.http.get<OAuthDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/create-user?code=${code}&state=${state}`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         'Content-Type': 'application/json' | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // /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 */ | ||||
|   saveToken(token: TokenDTO): void { | ||||
|     localStorage.setItem('jwt', token.token); | ||||
|   | ||||
| @@ -1,286 +1,303 @@ | ||||
| { | ||||
|     "header": { | ||||
|         "change_password": "Passwort ändern", | ||||
|         "settings": "Einstellungen", | ||||
|         "logout": "Ausloggen", | ||||
|         "header": "Krümmelmonster WI" | ||||
|     }, | ||||
|     "sidebar": { | ||||
|         "dashboard": "Dashboard", | ||||
|         "server": "Server", | ||||
|         "server_empty": "Kein Server ausgewählt", | ||||
|         "settings": "Einstellungen", | ||||
|         "members": "Mitglieder", | ||||
|         "administration": "Administration", | ||||
|         "config": "Konfiguration", | ||||
|         "auth_user_list": "Benutzer" | ||||
|     }, | ||||
|     "admin": { | ||||
|         "settings": { | ||||
|             "header": "Konfiguration", | ||||
|             "website": { | ||||
|                 "header": "Webseite", | ||||
|                 "frontend_version": "Webseite Version", | ||||
|                 "backend_version": "Server Version", | ||||
|                 "config_path": "Konfigurations-Dateipfad", | ||||
|                 "frontend_base_url": "Webseite Basis-URL", | ||||
|                 "backend_base_url": "Server Basis-URL", | ||||
|                 "token_expire_time": "Token Ablaufzeit", | ||||
|                 "refresh_token_expire_time": "Refresh Token Ablaufzeit" | ||||
|             }, | ||||
|             "e_mail": { | ||||
|                 "header": "E-Mail", | ||||
|                 "user": "Benutzer", | ||||
|                 "host": "Host", | ||||
|                 "port": "Port", | ||||
|                 "transceiver": "Absender", | ||||
|                 "e_mail_address": "E-Mail Adresse", | ||||
|                 "e_mail": "E-Mail", | ||||
|                 "send_e_mail": "E-Mail senden" | ||||
|             }, | ||||
|             "message": { | ||||
|                 "error": "Fehler", | ||||
|                 "could_not_send_mail": "E-Mail konte nicht gesendet werden!", | ||||
|                 "connection_failed": "Verbindung fehlgeschlagen", | ||||
|                 "connection_to_mail_failed": "Die Verbindung zum Mailserver konnte nicht hergestellt werden!", | ||||
|                 "mail_login_failed": "Die Anmeldung am Mailserver ist fehlgeschlagen!", | ||||
|                 "send_failed": "Senden fehlgeschlagen", | ||||
|                 "test_mail_not_send": "Die Test E-Mail konnte nicht gesendet werden!", | ||||
|                 "success": "Erfolg", | ||||
|                 "send_mail": "E-Mail wurde erfolgreich gesendet" | ||||
|             } | ||||
|         }, | ||||
|         "auth_users": { | ||||
|             "header": "Benutzer", | ||||
|             "of": "von", | ||||
|             "add": "Hinzufügen", | ||||
|             "reset_filters": "Filter zurücksetzen", | ||||
|             "users": "Benutzer", | ||||
|             "headers": { | ||||
|                 "users": "Benutzer", | ||||
|                 "first_name": "Vorname", | ||||
|                 "last_name": "Nachname", | ||||
|                 "e_mail": "E-Mail", | ||||
|                 "active": "Aktiv", | ||||
|                 "role": "Rolle", | ||||
|                 "password": "Passwort", | ||||
|                 "actions": "Aktionen" | ||||
|             }, | ||||
|             "no_entries_found": "Keine Einträge gefunden", | ||||
|             "message": { | ||||
|                 "invalid_email": "Ungültige E-Mail", | ||||
|                 "invalid_email_d": "Die E-Mail {{email}} ist nicht gültig!", | ||||
|                 "user_already_exists": "Benutzer existiert bereits", | ||||
|                 "user_already_exists_d": "Der Benutzer {{email}} existiert bereits!", | ||||
|                 "user_added": "Benutzer hinzugefügt", | ||||
|                 "user_added_d": "Benutzer {{email}} erfolgreich hinzugefügt", | ||||
|                 "user_change_failed": "Benutzer änderung fehlgeschlagen", | ||||
|                 "user_change_failed_d": "Benutzer {{email}} konnte nicht geändert werden!", | ||||
|                 "user_changed": "Benutzer geändert", | ||||
|                 "user_changed_d": "Benutzer {{email}} erfolgreich geändert", | ||||
|                 "cannot_delete_user": "Benutzer kann nicht gelöscht werden", | ||||
|                 "logon_with_another_user": "Loggen Sie sich mit einem anderen Benutzer ein, um diesen Benutzer zu löschen!", | ||||
|                 "user_delete": "Benutzer löschen", | ||||
|                 "user_delete_q": "Sind Sie sich sicher, dass Sie {{email}} löschen möchten?", | ||||
|                 "user_deleted": "Benutzer gelöscht", | ||||
|                 "user_deleted_d": "Benutzer {{email}} erfolgreich gelöscht" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "auth": { | ||||
|         "header": "Krümmelmonster WI", | ||||
|         "login": { | ||||
|             "e_mail": "E-Mail", | ||||
|             "password": "Passwort", | ||||
|             "login": "Einloggen", | ||||
|             "register": "Registrieren", | ||||
|             "forgot_password": "Passwort vergessen?", | ||||
|             "e_mail_required": "E-Mail benötigt", | ||||
|             "user_not_found": "Benutzer nicht gefunden", | ||||
|             "e_mail_not_confirmed": "E-Mail nicht bestätigt", | ||||
|             "password_required": "Passwort benötigt", | ||||
|             "wrong_password": "Falsches passwort" | ||||
|         }, | ||||
|         "register": { | ||||
|             "first_name": "Vorname", | ||||
|             "last_name": "Nachname", | ||||
|             "e_mail": "E-Mail", | ||||
|             "repeat_e_mail": "E-mail wiederholen", | ||||
|             "password": "Password", | ||||
|             "repeat_password": "password wiederholen", | ||||
|             "register": "Registrieren", | ||||
|             "login": "Einloggen", | ||||
|             "user_already_exists": "Benutzer existiert bereits", | ||||
|             "passwords_not_match": "Passwörter sitmmen nicht überein", | ||||
|             "e_mails_not_match": "E-Mails sitmmen nicht überein", | ||||
|             "first_name_required": "Vorname benötigt", | ||||
|             "last_name_required": "Nachname benötigt", | ||||
|             "e_mail_required": "E-Mail benötigt", | ||||
|             "password_required": "Passwort benötigt", | ||||
|             "first_name_invalid": "Vorname ungültig", | ||||
|             "last_name_invalid": "Nachname ungültig" | ||||
|         }, | ||||
|         "forgot_password": { | ||||
|             "e_mail": "E-Mail", | ||||
|             "send_confirmation_url": "Falls ein Benutzer mit der E-Mail gefunden wurde, wurde Betstätigungslink versendet", | ||||
|             "reset_password": "Passwort zurücksetzen", | ||||
|             "login": "Anmelden", | ||||
|             "register": "Registrieren", | ||||
|             "repeat_password": "Passwort wiederholen", | ||||
|             "passwords_do_not_match": "Die Passwörter stimmen nicht überein", | ||||
|             "password": "Passwort", | ||||
|             "message": { | ||||
|                 "reset_password": "Passwort zurückgesetzt", | ||||
|                 "reset_password_d": "Dein Passwort wurde zurückgesetzt" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "view": { | ||||
|         "dashboard": { | ||||
|             "header": "Dashboard", | ||||
|             "of": "von", | ||||
|             "servers": "Server", | ||||
|             "server": { | ||||
|                 "header": "Server", | ||||
|                 "member_count": "Mitglid(er)" | ||||
|             }, | ||||
|             "filter": { | ||||
|                 "name": "Name" | ||||
|             } | ||||
|         }, | ||||
|         "server": { | ||||
|             "header": "Server" | ||||
|         }, | ||||
|         "user-list": {}, | ||||
|         "change-password": { | ||||
|             "header": "Passwort ändern", | ||||
|             "wrong_password": "Falsches Passwort", | ||||
|             "passwords_do_not_match": "Die Passwörter stimmen nicht überein", | ||||
|             "password": "Passwort", | ||||
|             "active_password": "Aktuelles Passwort", | ||||
|             "new_password": "Neues Passwort", | ||||
|             "repeat_new_password": "Neues Passwort wiederholen", | ||||
|             "save": "Speichern", | ||||
|             "message": { | ||||
|                 "error": "Fehler", | ||||
|                 "password_cannot_be_changed": "Dein Passwort konnte nicht geändert werden!", | ||||
|                 "change_password": "Passwort geändert", | ||||
|                 "changed_password": "Dein Passwort wurde geändert" | ||||
|             } | ||||
|         }, | ||||
|         "user_settings": { | ||||
|             "header": "Einstellungen", | ||||
|             "first_name": "Vorname", | ||||
|             "last_name": "Nachname", | ||||
|             "e_mail": "E-Mail", | ||||
|             "password": "Passwort", | ||||
|             "e_mail_already_exists": "Die E-Mail wurde bereits vergeben", | ||||
|             "wrong_password": "Falsches Passwort", | ||||
|             "save": "Speichern", | ||||
|             "message": { | ||||
|                 "user_not_found": "Benutzer nicht gefunden", | ||||
|                 "user_not_found_d": "Der Benutzer konnte nicht gefunden werden!", | ||||
|                 "error": "Fehler", | ||||
|                 "could_not_change_settings": "Die Einstellungen konnten nicht geändert werden!", | ||||
|                 "changed_settings": "Die Einstellungen wurden geändert", | ||||
|                 "success": "Erfolg" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "footer": { | ||||
|         "imprint": "Impressum", | ||||
|         "backend": "Webseite", | ||||
|         "frontend": "API" | ||||
|     }, | ||||
|     "dialog": { | ||||
|         "confirm": "Bestätigen", | ||||
|         "abort": "Abbrechen" | ||||
|     }, | ||||
|     "general": { | ||||
|         "days": "Tage", | ||||
|         "minutes": "Minuten" | ||||
|     }, | ||||
|     "common": { | ||||
|         "bool_as_string": { | ||||
|             "true": "Ja", | ||||
|             "false": "Nein" | ||||
|         }, | ||||
|   "header": { | ||||
|     "change_password": "Passwort ändern", | ||||
|     "settings": "Einstellungen", | ||||
|     "logout": "Ausloggen", | ||||
|     "header": "Krümmelmonster WI" | ||||
|   }, | ||||
|   "sidebar": { | ||||
|     "dashboard": "Dashboard", | ||||
|     "server": "Server", | ||||
|     "server_empty": "Kein Server ausgewählt", | ||||
|     "settings": "Einstellungen", | ||||
|     "members": "Mitglieder", | ||||
|     "administration": "Administration", | ||||
|     "config": "Konfiguration", | ||||
|     "auth_user_list": "Benutzer" | ||||
|   }, | ||||
|   "admin": { | ||||
|     "settings": { | ||||
|       "header": "Konfiguration", | ||||
|       "website": { | ||||
|         "header": "Webseite", | ||||
|         "frontend_version": "Webseite Version", | ||||
|         "backend_version": "Server Version", | ||||
|         "config_path": "Konfigurations-Dateipfad", | ||||
|         "frontend_base_url": "Webseite Basis-URL", | ||||
|         "backend_base_url": "Server Basis-URL", | ||||
|         "token_expire_time": "Token Ablaufzeit", | ||||
|         "refresh_token_expire_time": "Refresh Token Ablaufzeit" | ||||
|       }, | ||||
|       "e_mail": { | ||||
|         "header": "E-Mail", | ||||
|         "user": "Benutzer", | ||||
|         "host": "Host", | ||||
|         "port": "Port", | ||||
|         "transceiver": "Absender", | ||||
|         "e_mail_address": "E-Mail Adresse", | ||||
|         "e_mail": "E-Mail", | ||||
|         "send_e_mail": "E-Mail senden" | ||||
|       }, | ||||
|       "message": { | ||||
|         "error": "Fehler", | ||||
|         "404": "404 - Der Eintrag konnte nicht gefunden werden" | ||||
|         "could_not_send_mail": "E-Mail konte nicht gesendet werden!", | ||||
|         "connection_failed": "Verbindung fehlgeschlagen", | ||||
|         "connection_to_mail_failed": "Die Verbindung zum Mailserver konnte nicht hergestellt werden!", | ||||
|         "mail_login_failed": "Die Anmeldung am Mailserver ist fehlgeschlagen!", | ||||
|         "send_failed": "Senden fehlgeschlagen", | ||||
|         "test_mail_not_send": "Die Test E-Mail konnte nicht gesendet werden!", | ||||
|         "success": "Erfolg", | ||||
|         "send_mail": "E-Mail wurde erfolgreich gesendet" | ||||
|       } | ||||
|     }, | ||||
|     "primeng": { | ||||
|         "startsWith": "Startet mit", | ||||
|         "contains": "Enthält", | ||||
|         "notContains": "Enthält nicht", | ||||
|         "endsWith": "Ended mit", | ||||
|         "equals": "Gleich", | ||||
|         "notEquals": "Nicht gleich", | ||||
|         "noFilter": "Kein Filter", | ||||
|         "lt": "Weniger als", | ||||
|         "lte": "Weniger als oder gleich", | ||||
|         "gt": "Größer als", | ||||
|         "gte": "Größer als doer gleich", | ||||
|         "is": "Ist", | ||||
|         "isNot": "Ist nicht", | ||||
|         "before": "Vorher", | ||||
|         "after": "Nachher", | ||||
|         "clear": "Zurücksetzen", | ||||
|         "apply": "Anwenden", | ||||
|         "matchAll": "Passend zu allem", | ||||
|         "matchAny": "Passend zu jedem", | ||||
|         "addRule": "Regel hinzufügen", | ||||
|         "removeRule": "Regel entfernen", | ||||
|         "accept": "Ja", | ||||
|         "reject": "Nein", | ||||
|         "choose": "Wählen", | ||||
|         "upload": "Hochladen", | ||||
|         "cancel": "Abbrechen", | ||||
|         "dayNames": [ | ||||
|             "Sonntag", | ||||
|             "Montag", | ||||
|             "Dienstag", | ||||
|             "Mittwoch", | ||||
|             "Donnerstag", | ||||
|             "Freitag", | ||||
|             "Samstag" | ||||
|         ], | ||||
|         "dayNamesShort": ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"], | ||||
|         "dayNamesMin": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], | ||||
|         "monthNames": [ | ||||
|             "Januar", | ||||
|             "Februar", | ||||
|             "März", | ||||
|             "April", | ||||
|             "Mai", | ||||
|             "Juni", | ||||
|             "Juli", | ||||
|             "August", | ||||
|             "September", | ||||
|             "Oktober", | ||||
|             "November", | ||||
|             "Dezember" | ||||
|         ], | ||||
|         "monthNamesShort": [ | ||||
|             "Jan", | ||||
|             "Feb", | ||||
|             "Mär", | ||||
|             "Apr", | ||||
|             "Mai", | ||||
|             "Jun", | ||||
|             "Jul", | ||||
|             "Aug", | ||||
|             "Sep", | ||||
|             "Okt", | ||||
|             "Nov", | ||||
|             "Dez" | ||||
|         ], | ||||
|         "today": "Heute", | ||||
|         "weekHeader": "Wk", | ||||
|         "weak": "Woche", | ||||
|         "medium": "Mittel", | ||||
|         "strong": "Stark", | ||||
|         "passwordPrompt": "Passwort eingeben", | ||||
|         "emptyMessage": "Keine Ergebnisse gefunden", | ||||
|         "emptyFilterMessage": "Keine Ergebnisse gefunden" | ||||
|     "auth_users": { | ||||
|       "header": "Benutzer", | ||||
|       "of": "von", | ||||
|       "add": "Hinzufügen", | ||||
|       "reset_filters": "Filter zurücksetzen", | ||||
|       "users": "Benutzer", | ||||
|       "headers": { | ||||
|         "users": "Benutzer", | ||||
|         "first_name": "Vorname", | ||||
|         "last_name": "Nachname", | ||||
|         "e_mail": "E-Mail", | ||||
|         "active": "Aktiv", | ||||
|         "role": "Rolle", | ||||
|         "password": "Passwort", | ||||
|         "actions": "Aktionen" | ||||
|       }, | ||||
|       "no_entries_found": "Keine Einträge gefunden", | ||||
|       "message": { | ||||
|         "invalid_email": "Ungültige E-Mail", | ||||
|         "invalid_email_d": "Die E-Mail {{email}} ist nicht gültig!", | ||||
|         "user_already_exists": "Benutzer existiert bereits", | ||||
|         "user_already_exists_d": "Der Benutzer {{email}} existiert bereits!", | ||||
|         "user_added": "Benutzer hinzugefügt", | ||||
|         "user_added_d": "Benutzer {{email}} erfolgreich hinzugefügt", | ||||
|         "user_change_failed": "Benutzer änderung fehlgeschlagen", | ||||
|         "user_change_failed_d": "Benutzer {{email}} konnte nicht geändert werden!", | ||||
|         "user_changed": "Benutzer geändert", | ||||
|         "user_changed_d": "Benutzer {{email}} erfolgreich geändert", | ||||
|         "cannot_delete_user": "Benutzer kann nicht gelöscht werden", | ||||
|         "logon_with_another_user": "Loggen Sie sich mit einem anderen Benutzer ein, um diesen Benutzer zu löschen!", | ||||
|         "user_delete": "Benutzer löschen", | ||||
|         "user_delete_q": "Sind Sie sich sicher, dass Sie {{email}} löschen möchten?", | ||||
|         "user_deleted": "Benutzer gelöscht", | ||||
|         "user_deleted_d": "Benutzer {{email}} erfolgreich gelöscht" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "auth": { | ||||
|     "header": "Krümmelmonster WI", | ||||
|     "login": { | ||||
|       "e_mail": "E-Mail", | ||||
|       "password": "Passwort", | ||||
|       "login": "Einloggen", | ||||
|       "register": "Registrieren", | ||||
|       "forgot_password": "Passwort vergessen?", | ||||
|       "e_mail_required": "E-Mail benötigt", | ||||
|       "user_not_found": "Benutzer nicht gefunden", | ||||
|       "e_mail_not_confirmed": "E-Mail nicht bestätigt", | ||||
|       "password_required": "Passwort benötigt", | ||||
|       "wrong_password": "Falsches passwort" | ||||
|     }, | ||||
|     "register": { | ||||
|       "first_name": "Vorname", | ||||
|       "last_name": "Nachname", | ||||
|       "e_mail": "E-Mail", | ||||
|       "repeat_e_mail": "E-mail wiederholen", | ||||
|       "password": "Password", | ||||
|       "repeat_password": "Password wiederholen", | ||||
|       "register": "Registrieren", | ||||
|       "register_with_discord": "Mit Discord Registrieren", | ||||
|       "login": "Einloggen", | ||||
|       "user_already_exists": "Benutzer existiert bereits", | ||||
|       "passwords_not_match": "Passwörter sitmmen nicht überein", | ||||
|       "e_mails_not_match": "E-Mails sitmmen nicht überein", | ||||
|       "first_name_required": "Vorname benötigt", | ||||
|       "last_name_required": "Nachname benötigt", | ||||
|       "e_mail_required": "E-Mail benötigt", | ||||
|       "password_required": "Passwort benötigt", | ||||
|       "first_name_invalid": "Vorname ungültig", | ||||
|       "last_name_invalid": "Nachname ungültig" | ||||
|     }, | ||||
|     "forgot_password": { | ||||
|       "e_mail": "E-Mail", | ||||
|       "send_confirmation_url": "Falls ein Benutzer mit der E-Mail gefunden wurde, wurde Betstätigungslink versendet", | ||||
|       "reset_password": "Passwort zurücksetzen", | ||||
|       "login": "Anmelden", | ||||
|       "register": "Registrieren", | ||||
|       "repeat_password": "Passwort wiederholen", | ||||
|       "passwords_do_not_match": "Die Passwörter stimmen nicht überein", | ||||
|       "password": "Passwort", | ||||
|       "message": { | ||||
|         "reset_password": "Passwort zurückgesetzt", | ||||
|         "reset_password_d": "Dein Passwort wurde zurückgesetzt" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "view": { | ||||
|     "dashboard": { | ||||
|       "header": "Dashboard", | ||||
|       "of": "von", | ||||
|       "servers": "Server", | ||||
|       "server": { | ||||
|         "header": "Server", | ||||
|         "member_count": "Mitglid(er)" | ||||
|       }, | ||||
|       "filter": { | ||||
|         "name": "Name" | ||||
|       } | ||||
|     }, | ||||
|     "server": { | ||||
|       "header": "Server" | ||||
|     }, | ||||
|     "user-list": {}, | ||||
|     "change-password": { | ||||
|       "header": "Passwort ändern", | ||||
|       "wrong_password": "Falsches Passwort", | ||||
|       "passwords_do_not_match": "Die Passwörter stimmen nicht überein", | ||||
|       "password": "Passwort", | ||||
|       "active_password": "Aktuelles Passwort", | ||||
|       "new_password": "Neues Passwort", | ||||
|       "repeat_new_password": "Neues Passwort wiederholen", | ||||
|       "save": "Speichern", | ||||
|       "message": { | ||||
|         "error": "Fehler", | ||||
|         "password_cannot_be_changed": "Dein Passwort konnte nicht geändert werden!", | ||||
|         "change_password": "Passwort geändert", | ||||
|         "changed_password": "Dein Passwort wurde geändert" | ||||
|       } | ||||
|     }, | ||||
|     "user_settings": { | ||||
|       "header": "Einstellungen", | ||||
|       "first_name": "Vorname", | ||||
|       "last_name": "Nachname", | ||||
|       "e_mail": "E-Mail", | ||||
|       "password": "Passwort", | ||||
|       "e_mail_already_exists": "Die E-Mail wurde bereits vergeben", | ||||
|       "wrong_password": "Falsches Passwort", | ||||
|       "save": "Speichern", | ||||
|       "message": { | ||||
|         "user_not_found": "Benutzer nicht gefunden", | ||||
|         "user_not_found_d": "Der Benutzer konnte nicht gefunden werden!", | ||||
|         "error": "Fehler", | ||||
|         "could_not_change_settings": "Die Einstellungen konnten nicht geändert werden!", | ||||
|         "changed_settings": "Die Einstellungen wurden geändert", | ||||
|         "success": "Erfolg" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "footer": { | ||||
|     "imprint": "Impressum", | ||||
|     "backend": "Webseite", | ||||
|     "frontend": "API" | ||||
|   }, | ||||
|   "dialog": { | ||||
|     "confirm": "Bestätigen", | ||||
|     "abort": "Abbrechen" | ||||
|   }, | ||||
|   "general": { | ||||
|     "days": "Tage", | ||||
|     "minutes": "Minuten" | ||||
|   }, | ||||
|   "common": { | ||||
|     "bool_as_string": { | ||||
|       "true": "Ja", | ||||
|       "false": "Nein" | ||||
|     }, | ||||
|     "error": "Fehler", | ||||
|     "404": "404 - Der Eintrag konnte nicht gefunden werden" | ||||
|   }, | ||||
|   "primeng": { | ||||
|     "startsWith": "Startet mit", | ||||
|     "contains": "Enthält", | ||||
|     "notContains": "Enthält nicht", | ||||
|     "endsWith": "Ended mit", | ||||
|     "equals": "Gleich", | ||||
|     "notEquals": "Nicht gleich", | ||||
|     "noFilter": "Kein Filter", | ||||
|     "lt": "Weniger als", | ||||
|     "lte": "Weniger als oder gleich", | ||||
|     "gt": "Größer als", | ||||
|     "gte": "Größer als doer gleich", | ||||
|     "is": "Ist", | ||||
|     "isNot": "Ist nicht", | ||||
|     "before": "Vorher", | ||||
|     "after": "Nachher", | ||||
|     "clear": "Zurücksetzen", | ||||
|     "apply": "Anwenden", | ||||
|     "matchAll": "Passend zu allem", | ||||
|     "matchAny": "Passend zu jedem", | ||||
|     "addRule": "Regel hinzufügen", | ||||
|     "removeRule": "Regel entfernen", | ||||
|     "accept": "Ja", | ||||
|     "reject": "Nein", | ||||
|     "choose": "Wählen", | ||||
|     "upload": "Hochladen", | ||||
|     "cancel": "Abbrechen", | ||||
|     "dayNames": [ | ||||
|       "Sonntag", | ||||
|       "Montag", | ||||
|       "Dienstag", | ||||
|       "Mittwoch", | ||||
|       "Donnerstag", | ||||
|       "Freitag", | ||||
|       "Samstag" | ||||
|     ], | ||||
|     "dayNamesShort": [ | ||||
|       "Son", | ||||
|       "Mon", | ||||
|       "Die", | ||||
|       "Mit", | ||||
|       "Don", | ||||
|       "Fre", | ||||
|       "Sam" | ||||
|     ], | ||||
|     "dayNamesMin": [ | ||||
|       "So", | ||||
|       "Mo", | ||||
|       "Di", | ||||
|       "Mi", | ||||
|       "Do", | ||||
|       "Fr", | ||||
|       "Sa" | ||||
|     ], | ||||
|     "monthNames": [ | ||||
|       "Januar", | ||||
|       "Februar", | ||||
|       "März", | ||||
|       "April", | ||||
|       "Mai", | ||||
|       "Juni", | ||||
|       "Juli", | ||||
|       "August", | ||||
|       "September", | ||||
|       "Oktober", | ||||
|       "November", | ||||
|       "Dezember" | ||||
|     ], | ||||
|     "monthNamesShort": [ | ||||
|       "Jan", | ||||
|       "Feb", | ||||
|       "Mär", | ||||
|       "Apr", | ||||
|       "Mai", | ||||
|       "Jun", | ||||
|       "Jul", | ||||
|       "Aug", | ||||
|       "Sep", | ||||
|       "Okt", | ||||
|       "Nov", | ||||
|       "Dez" | ||||
|     ], | ||||
|     "today": "Heute", | ||||
|     "weekHeader": "Wk", | ||||
|     "weak": "Woche", | ||||
|     "medium": "Mittel", | ||||
|     "strong": "Stark", | ||||
|     "passwordPrompt": "Passwort eingeben", | ||||
|     "emptyMessage": "Keine Ergebnisse gefunden", | ||||
|     "emptyFilterMessage": "Keine Ergebnisse gefunden" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -421,7 +421,7 @@ footer { | ||||
|     } | ||||
|  | ||||
|     .register-form-wrapper { | ||||
|         height: 550px; | ||||
|         height: 600px; | ||||
|     } | ||||
|  | ||||
|     .register-confirm-form-wrapper { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user