Added logic to register by discord #70

This commit is contained in:
Sven Heidemann 2022-10-20 09:47:23 +02:00
parent 0c42c6554c
commit d778bd2719
17 changed files with 725 additions and 452 deletions

View File

@ -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_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO 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.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO 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 async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass
@abstractmethod @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 @abstractmethod
async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass 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 async def add_auth_user_async(self, user_dto: AuthUserDTO): pass
@abstractmethod @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 @abstractmethod
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass

View File

@ -13,7 +13,8 @@
}, },
"DiscordAuthentication": { "DiscordAuthentication": {
"ClientSecret": "V3FTb3JYVFBiVktEeHZxdWJDWW4xcnBCbXRwdmpwcy0=", "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": [ "Scope": [
"identify", "identify",
"email" "email"

View File

@ -7,15 +7,17 @@ from cpl_core.mailing import EMailClientABC, EMailClientSettings
from cpl_core.utils import CredentialManager from cpl_core.utils import CredentialManager
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe from cpl_translation import TranslatePipe
from flask import jsonify from flask import jsonify, Response
from flask import request, session from flask import request, session
from requests_oauthlib import OAuth2Session from requests_oauthlib import OAuth2Session
from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings 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.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.model.o_auth_dto import OAuthDTO
from bot_api.route.route import Route from bot_api.route.route import Route
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum
@ -50,27 +52,26 @@ class AuthDiscordController:
self._mailer = mailer self._mailer = mailer
self._auth_service = auth_service self._auth_service = auth_service
@Route.get(f'{BasePath}/get-url') def _get_user_from_discord_response(self) -> dict:
async def get_url(self): discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope)
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)
token = discord.fetch_token( token = discord.fetch_token(
self._auth_settings.token_url, self._auth_settings.token_url,
client_secret=CredentialManager.decrypt(self._auth_settings.client_secret), client_secret=CredentialManager.decrypt(self._auth_settings.client_secret),
authorization_response=request.url, authorization_response=request.url,
) )
session['discord_token'] = token
discord = OAuth2Session(self._bot.user.id, 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, 0,
response['username'], response['username'],
response['discriminator'], response['discriminator'],
@ -80,4 +81,10 @@ class AuthDiscordController:
AuthRoleEnum.normal, AuthRoleEnum.normal,
response['id'] 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 return '', 200

View File

@ -8,14 +8,14 @@ class AuthUserDTO(DtoABC):
def __init__( def __init__(
self, self,
id: int, id: int = None,
first_name: str, first_name: str = None,
last_name: str, last_name: str = None,
email: str, email: str = None,
password: str, password: str = None,
confirmation_id: Optional[str], confirmation_id: Optional[str] = None,
auth_role: AuthRoleEnum, auth_role: AuthRoleEnum = None,
user_id: Optional[int], user_id: Optional[int] = None,
): ):
DtoABC.__init__(self) DtoABC.__init__(self)

View 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
}

View File

@ -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_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO 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.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
@ -190,9 +191,10 @@ class AuthService(AuthServiceABC):
users.total_count 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: 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: except Exception as e:
self._logger.error(__name__, f'AuthUser not found', e) self._logger.error(__name__, f'AuthUser not found', e)
raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}') 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) self._logger.error(__name__, f'Cannot add user with E-Mal {user_dto.email}', e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail") 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) db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
# user exists # user exists
if db_user is not None and db_user.user_id is not None: 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 # user exists but discord user id not set
elif db_user is not None and db_user.user_id is None: 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() user = self._users.get_users_by_discord_id(user_dto.user_id).single()
db_user.user_id = user.user_id db_user.user_id = user.user_id
self._auth_users.update_auth_user(db_user) db_user.oauth_id = None
self._db.save_changes()
return AUT.to_dto(db_user)
# user does not exists else:
await self.add_auth_user_async(user_dto) # user does not exists
db_user = self._auth_users.get_auth_user_by_email(user_dto.email) self._logger.debug(__name__, f'Auth user does not exist')
return AUT.to_dto(db_user, password=db_user.password) 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): async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None: if update_user_dto is None:

View File

@ -19,6 +19,7 @@ class AuthUserTransformer(TransformerABC):
None, None,
None, None,
None, None,
None,
datetime.now(tz=timezone.utc), datetime.now(tz=timezone.utc),
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
dto.user_id, dto.user_id,

View File

@ -27,6 +27,7 @@ class ApiMigration(MigrationABC):
`RefreshToken` VARCHAR(255), `RefreshToken` VARCHAR(255),
`ConfirmationId` VARCHAR(255) DEFAULT NULL, `ConfirmationId` VARCHAR(255) DEFAULT NULL,
`ForgotPasswordId` VARCHAR(255) DEFAULT NULL, `ForgotPasswordId` VARCHAR(255) DEFAULT NULL,
`OAuthId` VARCHAR(255) DEFAULT NULL,
`RefreshTokenExpiryTime` DATETIME(6) NOT NULL, `RefreshTokenExpiryTime` DATETIME(6) NOT NULL,
`AuthRole` INT NOT NULL DEFAULT '0', `AuthRole` INT NOT NULL DEFAULT '0',
`UserId` BIGINT DEFAULT NULL, `UserId` BIGINT DEFAULT NULL,

View File

@ -19,6 +19,7 @@ class AuthUser(TableABC):
refresh_token: Optional[str], refresh_token: Optional[str],
confirmation_id: Optional[str], confirmation_id: Optional[str],
forgot_password_id: Optional[str], forgot_password_id: Optional[str],
oauth_id: Optional[str],
refresh_token_expire_time: datetime, refresh_token_expire_time: datetime,
auth_role: AuthRoleEnum, auth_role: AuthRoleEnum,
user_id: Optional[int], 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._password_salt = uuid.uuid4() if password_salt is None else password_salt
self._refresh_token = refresh_token self._refresh_token = refresh_token
self._confirmation_id = confirmation_id self._confirmation_id = confirmation_id
self._oauth_id = oauth_id
self._forgot_password_id = forgot_password_id self._forgot_password_id = forgot_password_id
self._refresh_token_expire_time = refresh_token_expire_time self._refresh_token_expire_time = refresh_token_expire_time
@ -112,6 +114,14 @@ class AuthUser(TableABC):
def forgot_password_id(self, value: Optional[str]): def forgot_password_id(self, value: Optional[str]):
self._forgot_password_id = value 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 @property
def refresh_token_expire_time(self) -> datetime: def refresh_token_expire_time(self) -> datetime:
return self._refresh_token_expire_time return self._refresh_token_expire_time
@ -183,6 +193,7 @@ class AuthUser(TableABC):
`RefreshToken`, `RefreshToken`,
`ConfirmationId`, `ConfirmationId`,
`ForgotPasswordId`, `ForgotPasswordId`,
`OAuthId`,
`RefreshTokenExpiryTime`, `RefreshTokenExpiryTime`,
`AuthRole`, `AuthRole`,
`UserId`, `UserId`,
@ -198,6 +209,7 @@ class AuthUser(TableABC):
'{"NULL" if self._refresh_token is None else self._refresh_token}', '{"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._confirmation_id is None else self._confirmation_id}',
'{"NULL" if self._forgot_password_id is None else self._forgot_password_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._refresh_token_expire_time}',
{self._auth_role_id.value}, {self._auth_role_id.value},
{"NULL" if self._user_id is None else self._user_id}, {"NULL" if self._user_id is None else self._user_id},
@ -218,6 +230,7 @@ class AuthUser(TableABC):
`RefreshToken` = '{self._refresh_token}', `RefreshToken` = '{self._refresh_token}',
`ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}', `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}', `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}', `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}',
`AuthRole` = {self._auth_role_id.value}, `AuthRole` = {self._auth_role_id.value},
`UserId` = {"NULL" if self._user_id is None else self._user_id}, `UserId` = {"NULL" if self._user_id is None else self._user_id},

View File

@ -37,8 +37,9 @@ class AuthUserRepositoryService(AuthUserRepositoryABC):
self._get_value_from_result(result[7]), self._get_value_from_result(result[7]),
self._get_value_from_result(result[8]), self._get_value_from_result(result[8]),
self._get_value_from_result(result[9]), self._get_value_from_result(result[9]),
AuthRoleEnum(self._get_value_from_result(result[10])), self._get_value_from_result(result[10]),
self._get_value_from_result(result[11]), AuthRoleEnum(self._get_value_from_result(result[11])),
self._get_value_from_result(result[12]),
id=self._get_value_from_result(result[0]) id=self._get_value_from_result(result[0])
) )

View File

@ -0,0 +1,3 @@
export interface DiscordAuthURL {
loginUrl: string;
}

View File

@ -0,0 +1,6 @@
import { AuthUserDTO } from "./auth-user.dto";
export interface OAuthDTO {
user: AuthUserDTO;
oAuthId: string;
}

View File

@ -1,85 +1,91 @@
<section class="login-wrapper"> <section class="login-wrapper">
<div class="login-form-wrapper register-form-wrapper"> <div class="login-form-wrapper register-form-wrapper">
<div class="login-form"> <div class="login-form">
<form [formGroup]="loginForm"> <form [formGroup]="loginForm">
<h1>sh-edraft.de</h1> <h1>sh-edraft.de</h1>
<div class="input-field"> <div class="input-field">
<input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}" <input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}"
autocomplete="given-name"> autocomplete="given-name">
<div *ngIf="submitted" class="invalid-feedback"> <div *ngIf="submitted" class="invalid-feedback">
<div <div
*ngIf="loginForm.controls.firstName.errors && loginForm.controls.firstName.errors['required'] || authUserAtrErrors.firstName.required"> *ngIf="loginForm.controls.firstName.errors && loginForm.controls.firstName.errors['required'] || authUserAtrErrors.firstName.required">
{{'auth.register.first_name_required' | translate}}</div> {{'auth.register.first_name_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.firstName.wrongData">{{'auth.register.first_name_invalid' | translate}}</div> <div *ngIf="authUserAtrErrors.firstName.wrongData">{{'auth.register.first_name_invalid' | translate}}</div>
</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> </div>
</div>
<app-auth-header></app-auth-header> <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> </section>

View File

@ -1,19 +1,21 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from "@angular/router";
import { catchError } from 'rxjs/operators'; import { catchError, finalize } from "rxjs/operators";
import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; import { AuthErrorMessages } from "src/app/models/auth/auth-error-messages.enum";
import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; import { AuthUserDTO } from "src/app/models/auth/auth-user.dto";
import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; import { AuthUserAtrErrors } from "src/app/models/auth/auth-user-atr-errors";
import { ErrorDTO } from 'src/app/models/error/error-dto'; import { ErrorDTO } from "src/app/models/error/error-dto";
import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; import { ServiceErrorCode } from "src/app/models/error/service-error-code.enum";
import { AuthService } from 'src/app/services/auth/auth.service'; import { AuthService } from "src/app/services/auth/auth.service";
import { SpinnerService } from 'src/app/services/spinner/spinner.service'; import { SpinnerService } from "src/app/services/spinner/spinner.service";
import { throwError } from "rxjs";
import { OAuthDTO } from "../../../../models/auth/oauth.dto";
@Component({ @Component({
selector: 'app-registration', selector: "app-registration",
templateUrl: './registration.component.html', templateUrl: "./registration.component.html",
styleUrls: ['./registration.component.scss'] styleUrls: ["./registration.component.scss"]
}) })
export class RegistrationComponent implements OnInit { export class RegistrationComponent implements OnInit {
@ -35,6 +37,11 @@ export class RegistrationComponent implements OnInit {
showEMailConfirmation = false; showEMailConfirmation = false;
showEMailConfirmationError = false; showEMailConfirmationError = false;
code!: string;
state!: string;
user!: AuthUserDTO;
oAuthId!: string;
constructor( constructor(
private authService: AuthService, private authService: AuthService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
@ -45,16 +52,64 @@ export class RegistrationComponent implements OnInit {
this.spinnerService.showSpinner(); this.spinnerService.showSpinner();
this.authService.isUserLoggedInAsync().then(res => { this.authService.isUserLoggedInAsync().then(res => {
if (res) { if (res) {
this.router.navigate(['/dashboard']); this.router.navigate(["/dashboard"]);
} }
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
}); });
} }
ngOnInit(): void { 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.initLoginForm();
this.resetStateFlags(); this.resetStateFlags();
this.confirmEMail(); this.confirmEMail();
this.spinnerService.hideSpinner();
} }
resetStateFlags(): void { resetStateFlags(): void {
@ -66,18 +121,23 @@ export class RegistrationComponent implements OnInit {
} }
login(): void { login(): void {
this.router.navigate(['/auth/login']); this.router.navigate(["/auth/login"]);
} }
initLoginForm(): void { initLoginForm(): void {
this.loginForm = this.formBuilder.group({ this.loginForm = this.formBuilder.group({
firstName: ['', Validators.required], firstName: [this.user ? this.user.firstName : "", Validators.required],
lastName: ['', Validators.required], lastName: [this.user ? this.user.lastName : "", Validators.required],
email: ['', [Validators.required, Validators.email]], email: [this.user ? this.user.email : "", [Validators.required, Validators.email]],
emailRepeat: ['', [Validators.required, Validators.email]], emailRepeat: [this.user ? this.user.email : "", [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]], password: [this.user ? this.user.password : "", [Validators.required, Validators.minLength(8)]],
passwordRepeat: ['', [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 { register(): void {
@ -100,13 +160,49 @@ export class RegistrationComponent implements OnInit {
} }
this.spinnerService.showSpinner(); 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 = { const user: AuthUserDTO = {
firstName: this.loginForm.value.firstName ?? null, firstName: this.loginForm.value.firstName ?? null,
lastName: this.loginForm.value.lastName ?? null, lastName: this.loginForm.value.lastName ?? null,
email: this.loginForm.value.email ?? null, email: this.loginForm.value.email ?? null,
password: this.loginForm.value.password ?? null password: this.loginForm.value.password ?? null
}; };
this.authService.register(user) this.authService.register(user)
.pipe(catchError(error => { .pipe(catchError(error => {
if (error.error !== null) { if (error.error !== null) {
@ -121,24 +217,30 @@ export class RegistrationComponent implements OnInit {
})) }))
.subscribe(resp => { .subscribe(resp => {
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
this.router.navigate(['/auth/login']); this.router.navigate(["/auth/login"]);
}); });
} }
confirmEMail(): void { confirmEMail(): void {
const id = this.route.snapshot.params['id']; const id = this.route.snapshot.params["id"];
if (id) { if (id) {
this.spinnerService.showSpinner(); this.spinnerService.showSpinner();
this.authService.confirmEMail(id) this.authService.confirmEMail(id)
.pipe(catchError(error => { .pipe(catchError(error => {
this.router.navigate(['/auth/login']); this.router.navigate(["/auth/login"]);
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
throw error; throw error;
})) }))
.subscribe(resp => { .subscribe(resp => {
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
this.router.navigate(['/auth/login']); this.router.navigate(["/auth/login"]);
}); });
} }
} }
discordLogin() {
this.authService.getDiscordAuthURL().subscribe(url => {
window.location.href = url.loginUrl;
});
}
} }

View File

@ -1,20 +1,22 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'; 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 { firstValueFrom, Observable, Subject, Subscription } from 'rxjs'; import { firstValueFrom, Observable, Subject, Subscription } 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";
import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; import { AuthUserDTO } from "src/app/models/auth/auth-user.dto";
import { EMailStringDTO } from 'src/app/models/auth/email-string.dto'; import { EMailStringDTO } from "src/app/models/auth/email-string.dto";
import { ResetPasswordDTO } from 'src/app/models/auth/reset-password.dto'; import { ResetPasswordDTO } from "src/app/models/auth/reset-password.dto";
import { TokenDTO } from 'src/app/models/auth/token.dto'; import { TokenDTO } from "src/app/models/auth/token.dto";
import { UpdateUserDTO } from 'src/app/models/auth/update-user.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 { 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 { GetFilteredAuthUsersResultDTO } from "src/app/models/selection/auth-user/get-filtered-auth-users-result.dto";
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 { OAuthDTO } from "../../models/auth/oauth.dto";
@Injectable({ @Injectable({
providedIn: 'root' 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 */ /* utils */
saveToken(token: TokenDTO): void { saveToken(token: TokenDTO): void {
localStorage.setItem('jwt', token.token); localStorage.setItem('jwt', token.token);

View File

@ -1,286 +1,303 @@
{ {
"header": { "header": {
"change_password": "Passwort ändern", "change_password": "Passwort ändern",
"settings": "Einstellungen", "settings": "Einstellungen",
"logout": "Ausloggen", "logout": "Ausloggen",
"header": "Krümmelmonster WI" "header": "Krümmelmonster WI"
}, },
"sidebar": { "sidebar": {
"dashboard": "Dashboard", "dashboard": "Dashboard",
"server": "Server", "server": "Server",
"server_empty": "Kein Server ausgewählt", "server_empty": "Kein Server ausgewählt",
"settings": "Einstellungen", "settings": "Einstellungen",
"members": "Mitglieder", "members": "Mitglieder",
"administration": "Administration", "administration": "Administration",
"config": "Konfiguration", "config": "Konfiguration",
"auth_user_list": "Benutzer" "auth_user_list": "Benutzer"
}, },
"admin": { "admin": {
"settings": { "settings": {
"header": "Konfiguration", "header": "Konfiguration",
"website": { "website": {
"header": "Webseite", "header": "Webseite",
"frontend_version": "Webseite Version", "frontend_version": "Webseite Version",
"backend_version": "Server Version", "backend_version": "Server Version",
"config_path": "Konfigurations-Dateipfad", "config_path": "Konfigurations-Dateipfad",
"frontend_base_url": "Webseite Basis-URL", "frontend_base_url": "Webseite Basis-URL",
"backend_base_url": "Server Basis-URL", "backend_base_url": "Server Basis-URL",
"token_expire_time": "Token Ablaufzeit", "token_expire_time": "Token Ablaufzeit",
"refresh_token_expire_time": "Refresh Token Ablaufzeit" "refresh_token_expire_time": "Refresh Token Ablaufzeit"
}, },
"e_mail": { "e_mail": {
"header": "E-Mail", "header": "E-Mail",
"user": "Benutzer", "user": "Benutzer",
"host": "Host", "host": "Host",
"port": "Port", "port": "Port",
"transceiver": "Absender", "transceiver": "Absender",
"e_mail_address": "E-Mail Adresse", "e_mail_address": "E-Mail Adresse",
"e_mail": "E-Mail", "e_mail": "E-Mail",
"send_e_mail": "E-Mail senden" "send_e_mail": "E-Mail senden"
}, },
"message": { "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"
},
"error": "Fehler", "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": { "auth_users": {
"startsWith": "Startet mit", "header": "Benutzer",
"contains": "Enthält", "of": "von",
"notContains": "Enthält nicht", "add": "Hinzufügen",
"endsWith": "Ended mit", "reset_filters": "Filter zurücksetzen",
"equals": "Gleich", "users": "Benutzer",
"notEquals": "Nicht gleich", "headers": {
"noFilter": "Kein Filter", "users": "Benutzer",
"lt": "Weniger als", "first_name": "Vorname",
"lte": "Weniger als oder gleich", "last_name": "Nachname",
"gt": "Größer als", "e_mail": "E-Mail",
"gte": "Größer als doer gleich", "active": "Aktiv",
"is": "Ist", "role": "Rolle",
"isNot": "Ist nicht", "password": "Passwort",
"before": "Vorher", "actions": "Aktionen"
"after": "Nachher", },
"clear": "Zurücksetzen", "no_entries_found": "Keine Einträge gefunden",
"apply": "Anwenden", "message": {
"matchAll": "Passend zu allem", "invalid_email": "Ungültige E-Mail",
"matchAny": "Passend zu jedem", "invalid_email_d": "Die E-Mail {{email}} ist nicht gültig!",
"addRule": "Regel hinzufügen", "user_already_exists": "Benutzer existiert bereits",
"removeRule": "Regel entfernen", "user_already_exists_d": "Der Benutzer {{email}} existiert bereits!",
"accept": "Ja", "user_added": "Benutzer hinzugefügt",
"reject": "Nein", "user_added_d": "Benutzer {{email}} erfolgreich hinzugefügt",
"choose": "Wählen", "user_change_failed": "Benutzer änderung fehlgeschlagen",
"upload": "Hochladen", "user_change_failed_d": "Benutzer {{email}} konnte nicht geändert werden!",
"cancel": "Abbrechen", "user_changed": "Benutzer geändert",
"dayNames": [ "user_changed_d": "Benutzer {{email}} erfolgreich geändert",
"Sonntag", "cannot_delete_user": "Benutzer kann nicht gelöscht werden",
"Montag", "logon_with_another_user": "Loggen Sie sich mit einem anderen Benutzer ein, um diesen Benutzer zu löschen!",
"Dienstag", "user_delete": "Benutzer löschen",
"Mittwoch", "user_delete_q": "Sind Sie sich sicher, dass Sie {{email}} löschen möchten?",
"Donnerstag", "user_deleted": "Benutzer gelöscht",
"Freitag", "user_deleted_d": "Benutzer {{email}} erfolgreich gelöscht"
"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": {
"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"
}
} }

View File

@ -421,7 +421,7 @@ footer {
} }
.register-form-wrapper { .register-form-wrapper {
height: 550px; height: 600px;
} }
.register-confirm-form-wrapper { .register-confirm-form-wrapper {