Merge pull request '0.3 - Login per Discord (#128)' (#129) from #128 into 0.3

Reviewed-on: sh-edraft.de/kd_discord_bot#129
Reviewed-by: Ebola-Chan <nick.jungmann@gmail.com>
Closes #128
This commit is contained in:
Sven Heidemann 2022-11-20 16:54:03 +01:00
commit 840da350e4
13 changed files with 210 additions and 295 deletions

View File

@ -70,6 +70,9 @@ class AuthServiceABC(ABC):
@abstractmethod @abstractmethod
async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass
@abstractmethod
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO: pass
@abstractmethod @abstractmethod
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass

View File

@ -82,8 +82,18 @@ class AuthDiscordController:
), response['id']) ), response['id'])
return jsonify(result.to_dict()) return jsonify(result.to_dict())
@Route.post(f'{BasePath}/register') @Route.get(f'{BasePath}/login')
async def discord_register(self): async def discord_login(self) -> Response:
dto: OAuthDTO = JSONProcessor.process(OAuthDTO, request.get_json(force=True, silent=True)) response = self._get_user_from_discord_response()
await self._auth_service.add_auth_user_by_oauth_async(dto) dto = AuthUserDTO(
return '', 200 0,
response['username'],
response['discriminator'],
response['email'],
str(uuid.uuid4()),
None,
AuthRoleEnum.normal
)
result = await self._auth_service.login_discord_async(dto)
return jsonify(result.to_dict())

View File

@ -460,6 +460,24 @@ class AuthService(AuthServiceABC):
self._db.save_changes() self._db.save_changes()
return TokenDTO(token, refresh_token) return TokenDTO(token, refresh_token)
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, 'User not set')
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None:
await self.add_auth_user_async(user_dto)
# raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
token = self.generate_token(db_user)
refresh_token = self._create_and_save_refresh_token(db_user)
if db_user.forgot_password_id is not None:
db_user.forgot_password_id = None
self._db.save_changes()
return TokenDTO(token, refresh_token)
async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO:
if token_dto is None: if token_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set')

View File

@ -1,12 +1,12 @@
{ {
"name": "kdb-web", "name": "kdb-web",
"version": "0.3.dev70", "version": "0.3.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "kdb-web", "name": "kdb-web",
"version": "0.3.dev70", "version": "0.3.0",
"dependencies": { "dependencies": {
"@angular/animations": "^14.0.0", "@angular/animations": "^14.0.0",
"@angular/common": "^14.0.0", "@angular/common": "^14.0.0",
@ -25,7 +25,6 @@
"primeng": "^14.1.2", "primeng": "^14.1.2",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"socket.io-client": "^4.5.3", "socket.io-client": "^4.5.3",
"tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
@ -33,14 +32,14 @@
"@angular/cli": "~14.0.0", "@angular/cli": "~14.0.0",
"@angular/compiler-cli": "^14.0.0", "@angular/compiler-cli": "^14.0.0",
"@types/jasmine": "~4.0.0", "@types/jasmine": "~4.0.0",
"@types/node": "^18.8.3", "@types/node": "^18.11.9",
"jasmine-core": "~4.1.0", "jasmine-core": "~4.1.0",
"karma": "~6.3.0", "karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.0.0", "karma-jasmine": "~5.0.0",
"karma-jasmine-html-reporter": "~1.7.0", "karma-jasmine-html-reporter": "~1.7.0",
"ts-node": "~8.3.0", "tslib": "^2.4.1",
"typescript": "~4.7.2" "typescript": "~4.7.2"
} }
}, },
@ -222,6 +221,12 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true "dev": true
}, },
"node_modules/@angular-devkit/build-angular/node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
"dev": true
},
"node_modules/@angular-devkit/build-webpack": { "node_modules/@angular-devkit/build-webpack": {
"version": "0.1402.6", "version": "0.1402.6",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.6.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.6.tgz",
@ -3200,9 +3205,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.11.0", "version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
"dev": true "dev": true
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
@ -3705,12 +3710,6 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0" "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
} }
}, },
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/argparse": { "node_modules/argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -4982,15 +4981,6 @@
"integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==",
"dev": true "dev": true
}, },
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -7881,12 +7871,6 @@
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/make-fetch-happen": { "node_modules/make-fetch-happen": {
"version": "9.1.0", "version": "9.1.0",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
@ -11730,32 +11714,10 @@
"tree-kill": "cli.js" "tree-kill": "cli.js"
} }
}, },
"node_modules/ts-node": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
"integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
"dev": true,
"dependencies": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "^3.0.0"
},
"bin": {
"ts-node": "dist/bin.js"
},
"engines": {
"node": ">=4.2.0"
},
"peerDependencies": {
"typescript": ">=2.0"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.4.0", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
}, },
"node_modules/type-fest": { "node_modules/type-fest": {
"version": "0.21.3", "version": "0.21.3",
@ -12510,15 +12472,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/zone.js": { "node_modules/zone.js": {
"version": "0.11.8", "version": "0.11.8",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz",
@ -12659,6 +12612,12 @@
"dev": true "dev": true
} }
} }
},
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
"dev": true
} }
} }
}, },
@ -14719,9 +14678,9 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "18.11.0", "version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
"dev": true "dev": true
}, },
"@types/parse-json": { "@types/parse-json": {
@ -15153,12 +15112,6 @@
"readable-stream": "^3.6.0" "readable-stream": "^3.6.0"
} }
}, },
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -16095,12 +16048,6 @@
"integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==",
"dev": true "dev": true
}, },
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"dir-glob": { "dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -18187,12 +18134,6 @@
} }
} }
}, },
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"make-fetch-happen": { "make-fetch-happen": {
"version": "9.1.0", "version": "9.1.0",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
@ -20975,23 +20916,10 @@
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true "dev": true
}, },
"ts-node": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
"integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "^3.0.0"
}
},
"tslib": { "tslib": {
"version": "2.4.0", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
}, },
"type-fest": { "type-fest": {
"version": "0.21.3", "version": "0.21.3",
@ -21518,12 +21446,6 @@
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true "dev": true
}, },
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
},
"zone.js": { "zone.js": {
"version": "0.11.8", "version": "0.11.8",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "kdb-web", "name": "kdb-web",
"version": "0.3.0", "version": "0.3.dev128",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"update-version": "ts-node-esm update-version.ts", "update-version": "ts-node-esm update-version.ts",
@ -33,7 +33,6 @@
"primeng": "^14.1.2", "primeng": "^14.1.2",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"socket.io-client": "^4.5.3", "socket.io-client": "^4.5.3",
"tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
@ -41,13 +40,14 @@
"@angular/cli": "~14.0.0", "@angular/cli": "~14.0.0",
"@angular/compiler-cli": "^14.0.0", "@angular/compiler-cli": "^14.0.0",
"@types/jasmine": "~4.0.0", "@types/jasmine": "~4.0.0",
"@types/node": "^18.8.3", "@types/node": "^18.11.9",
"jasmine-core": "~4.1.0", "jasmine-core": "~4.1.0",
"karma": "~6.3.0", "karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.0.0", "karma-jasmine": "~5.0.0",
"karma-jasmine-html-reporter": "~1.7.0", "karma-jasmine-html-reporter": "~1.7.0",
"tslib": "^2.4.1",
"typescript": "~4.7.2" "typescript": "~4.7.2"
} }
} }

View File

@ -41,6 +41,11 @@
<button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()" <button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()"
[disabled]="loginForm.invalid"></button> [disabled]="loginForm.invalid"></button>
</div> </div>
<div class="login-form-sub-button-wrapper" *ngIf="!code && !state">
<div class="login-form-sub-btn-wrapper">
<button pButton label="{{'auth.login.login_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-button-wrapper">
<div class="login-form-sub-btn-wrapper"> <div class="login-form-sub-btn-wrapper">
<button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn" <button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn"

View File

@ -1,20 +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 { AuthService } from 'src/app/services/auth/auth.service'; import { AuthService } from "src/app/services/auth/auth.service";
import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; import { AuthUserDTO } from "src/app/models/auth/auth-user.dto";
import { Router } from '@angular/router'; import { ActivatedRoute, Router } from "@angular/router";
import { catchError } from 'rxjs/operators'; import { catchError } from "rxjs/operators";
import { ErrorDTO } from 'src/app/models/error/error-dto'; import { ErrorDTO } from "src/app/models/error/error-dto";
import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; import { AuthErrorMessages } from "src/app/models/auth/auth-error-messages.enum";
import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; import { ServiceErrorCode } from "src/app/models/error/service-error-code.enum";
import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; import { AuthUserAtrErrors } from "src/app/models/auth/auth-user-atr-errors";
import { SpinnerService } from 'src/app/services/spinner/spinner.service'; import { SpinnerService } from "src/app/services/spinner/spinner.service";
import { ThemeService } from 'src/app/services/theme/theme.service'; import { ThemeService } from "src/app/services/theme/theme.service";
import { throwError } from "rxjs";
@Component({ @Component({
selector: 'app-login', selector: "app-login",
templateUrl: './login.component.html', templateUrl: "./login.component.html",
styleUrls: ['./login.component.scss'] styleUrls: ["./login.component.scss"]
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit {
@ -25,45 +26,83 @@ export class LoginComponent implements OnInit {
submitted = false; submitted = false;
authUserAtrErrors!: AuthUserAtrErrors; authUserAtrErrors!: AuthUserAtrErrors;
code!: string;
state!: string;
user!: AuthUserDTO;
oAuthId!: string;
constructor( constructor(
private authService: AuthService, private authService: AuthService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private router: Router, private router: Router,
private spinnerService: SpinnerService, private spinnerService: SpinnerService,
private themeService: ThemeService private themeService: ThemeService,
) { } private route: ActivatedRoute
) {
}
ngOnInit(): void { ngOnInit(): void {
this.spinnerService.showSpinner(); this.spinnerService.showSpinner();
this.authService.isUserLoggedInAsync().then(result => { this.authService.isUserLoggedInAsync().then(result => {
if (result) { if (result) {
this.router.navigate(['/dashboard']); this.router.navigate(["/dashboard"]);
return;
} }
this.checkDiscordLogin();
this.initLoginForm(); this.initLoginForm();
this.resetStateFlags(); this.resetStateFlags();
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
}); });
} }
checkDiscordLogin() {
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;
}
this.code = params["code"];
this.state = params["state"];
this.authService.discordLogin(this.code, this.state).pipe(catchError(err => {
this.spinnerService.hideSpinner();
this.router.navigate(["auth", "login"]).then(() => {
});
return throwError(() => err);
})).subscribe(token => {
this.authService.saveToken(token);
this.themeService.loadTheme();
this.themeService.loadMenu();
this.spinnerService.hideSpinner();
this.router.navigate(["/dashboard"]);
});
}
);
}
resetStateFlags(): void { resetStateFlags(): void {
this.authUserAtrErrors = new AuthUserAtrErrors(); this.authUserAtrErrors = new AuthUserAtrErrors();
} }
initLoginForm(): void { initLoginForm(): void {
this.loginForm = this.formBuilder.group({ this.loginForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]], email: ["", [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]] password: ["", [Validators.required, Validators.minLength(8)]]
}); });
} }
register(): void { register(): void {
this.router.navigate(['/auth/register']); this.router.navigate(["/auth/register"]);
} }
forgotPassword(): void { forgotPassword(): void {
this.router.navigate(['/auth/forgot-password']); this.router.navigate(["/auth/forgot-password"]);
} }
login(): void { login(): void {
@ -76,8 +115,8 @@ export class LoginComponent implements OnInit {
this.spinnerService.showSpinner(); this.spinnerService.showSpinner();
const user: AuthUserDTO = { const user: AuthUserDTO = {
firstName: '', firstName: "",
lastName: '', lastName: "",
email: this.loginForm.value.email ?? null, email: this.loginForm.value.email ?? null,
password: this.loginForm.value.password ?? null password: this.loginForm.value.password ?? null
}; };
@ -107,7 +146,13 @@ export class LoginComponent implements OnInit {
this.themeService.loadTheme(); this.themeService.loadTheme();
this.themeService.loadMenu(); this.themeService.loadMenu();
this.spinnerService.hideSpinner(); this.spinnerService.hideSpinner();
this.router.navigate(['/dashboard']); this.router.navigate(["/dashboard"]);
});
}
discordLogin() {
this.authService.getDiscordAuthURL().subscribe(url => {
window.location.href = url.loginUrl;
}); });
} }

View File

@ -72,12 +72,6 @@
[disabled]="loginForm.invalid"></button> [disabled]="loginForm.invalid"></button>
</div> </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-button-wrapper">
<div class="login-form-sub-btn-wrapper"> <div class="login-form-sub-btn-wrapper">
<button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button> <button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button>

View File

@ -34,14 +34,6 @@ export class RegistrationComponent implements OnInit {
password: false password: false
}; };
showEMailConfirmation = 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,
@ -62,49 +54,8 @@ export class RegistrationComponent implements OnInit {
this.confirmEMail(); this.confirmEMail();
this.initData(); this.initData();
this.spinnerService.showSpinner(); 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();
} }
);
this.initData();
}
);
}
initData() { initData() {
this.initLoginForm(); this.initLoginForm();
@ -126,18 +77,13 @@ export class RegistrationComponent implements OnInit {
initLoginForm(): void { initLoginForm(): void {
this.loginForm = this.formBuilder.group({ this.loginForm = this.formBuilder.group({
firstName: [this.user ? this.user.firstName : "", Validators.required], firstName: ["", Validators.required],
lastName: [this.user ? this.user.lastName : "", Validators.required], lastName: ["", Validators.required],
email: [this.user ? this.user.email : "", [Validators.required, Validators.email]], email: ["", [Validators.required, Validators.email]],
emailRepeat: [this.user ? this.user.email : "", [Validators.required, Validators.email]], emailRepeat: ["", [Validators.required, Validators.email]],
password: [this.user ? this.user.password : "", [Validators.required, Validators.minLength(8)]], password: ["", [Validators.required, Validators.minLength(8)]],
passwordRepeat: [this.user ? this.user.password : "", [Validators.required, Validators.minLength(8)]] passwordRepeat: ["", [Validators.required, Validators.minLength(8)]]
}); });
if (this.user) {
this.loginForm.controls.email.disable();
this.loginForm.controls.emailRepeat.disable();
}
} }
register(): void { register(): void {
@ -160,42 +106,10 @@ export class RegistrationComponent implements OnInit {
} }
this.spinnerService.showSpinner(); this.spinnerService.showSpinner();
if (this.user && this.oAuthId) {
this.registerWithOAuth();
return;
}
this.registerLocal(); 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() { private registerLocal() {
const user: AuthUserDTO = { const user: AuthUserDTO = {
firstName: this.loginForm.value.firstName ?? null, firstName: this.loginForm.value.firstName ?? null,
@ -237,10 +151,4 @@ export class RegistrationComponent implements OnInit {
}); });
} }
} }
discordLogin() {
this.authService.getDiscordAuthURL().subscribe(url => {
window.location.href = url.loginUrl;
});
}
} }

View File

@ -167,6 +167,7 @@ export class AuthService {
}) })
}); });
} }
discordCreateUser(code: string, state: string) { discordCreateUser(code: string, state: string) {
return this.http.get<OAuthDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/create-user?code=${code}&state=${state}`, { return this.http.get<OAuthDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/create-user?code=${code}&state=${state}`, {
headers: new HttpHeaders({ headers: new HttpHeaders({
@ -175,6 +176,14 @@ export class AuthService {
}); });
} }
discordLogin(code: string, state: string): Observable<TokenDTO> {
return this.http.get<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/login?code=${code}&state=${state}`, {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
});
}
// /api/auth/discord/register?code= // /api/auth/discord/register?code=
discordRegister(oAuthDTO: OAuthDTO) { discordRegister(oAuthDTO: OAuthDTO) {
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, { return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, {

View File

@ -3,7 +3,7 @@
"WebVersion": { "WebVersion": {
"Major": "0", "Major": "0",
"Minor": "3", "Minor": "3",
"Micro": "dev70" "Micro": "dev128"
}, },
"Themes": [ "Themes": [
{ {

View File

@ -93,6 +93,7 @@
"e_mail": "E-Mail", "e_mail": "E-Mail",
"password": "Passwort", "password": "Passwort",
"login": "Einloggen", "login": "Einloggen",
"login_with_discord": "Mit Discord Einloggen",
"register": "Registrieren", "register": "Registrieren",
"forgot_password": "Passwort vergessen?", "forgot_password": "Passwort vergessen?",
"e_mail_required": "E-Mail benötigt", "e_mail_required": "E-Mail benötigt",

View File

@ -373,7 +373,7 @@ footer {
.login-form-wrapper, .login-form-wrapper,
.auth-header { .auth-header {
width: 350px; width: 350px;
height: 350px; height: 450px;
display: flex; display: flex;
justify-content: center; justify-content: center;