Added flask support #70 #75 #71

Merged
edraft merged 107 commits from #70 into 0.3 2022-11-05 13:55:42 +01:00
17 changed files with 725 additions and 452 deletions
Showing only changes of commit d778bd2719 - Show all commits

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_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

View File

@ -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"

View File

@ -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

View File

@ -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

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_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:

View File

@ -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,

View File

@ -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',
edraft marked this conversation as resolved Outdated

Warum ist der Defaultwert für ein Integer als ein String angegeben?

Warum ist der Defaultwert für ein Integer als ein String angegeben?
`UserId` BIGINT DEFAULT NULL,

View File

@ -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},

View File

@ -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])
)

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">
<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>

View File

@ -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;
});
}
}

View File

@ -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);

View File

@ -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"
}
}

View File

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