0.3 - Login per Discord (#128) #129
| @@ -70,6 +70,9 @@ class AuthServiceABC(ABC): | ||||
|     @abstractmethod | ||||
|     async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO: pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass | ||||
|  | ||||
|   | ||||
| @@ -82,8 +82,18 @@ class AuthDiscordController: | ||||
|         ), 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 | ||||
|     @Route.get(f'{BasePath}/login') | ||||
|     async def discord_login(self) -> Response: | ||||
|         response = self._get_user_from_discord_response() | ||||
|         dto = AuthUserDTO( | ||||
|             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()) | ||||
|   | ||||
| @@ -460,6 +460,24 @@ class AuthService(AuthServiceABC): | ||||
|         self._db.save_changes() | ||||
|         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: | ||||
|         if token_dto is None: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') | ||||
|   | ||||
							
								
								
									
										134
									
								
								kdb-web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										134
									
								
								kdb-web/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| { | ||||
|     "name": "kdb-web", | ||||
|     "version": "0.3.dev70", | ||||
|     "version": "0.3.0", | ||||
|     "lockfileVersion": 2, | ||||
|     "requires": true, | ||||
|     "packages": { | ||||
|         "": { | ||||
|             "name": "kdb-web", | ||||
|             "version": "0.3.dev70", | ||||
|             "version": "0.3.0", | ||||
|             "dependencies": { | ||||
|                 "@angular/animations": "^14.0.0", | ||||
|                 "@angular/common": "^14.0.0", | ||||
| @@ -25,7 +25,6 @@ | ||||
|                 "primeng": "^14.1.2", | ||||
|                 "rxjs": "~7.5.0", | ||||
|                 "socket.io-client": "^4.5.3", | ||||
|                 "tslib": "^2.3.0", | ||||
|                 "zone.js": "~0.11.4" | ||||
|             }, | ||||
|             "devDependencies": { | ||||
| @@ -33,14 +32,14 @@ | ||||
|                 "@angular/cli": "~14.0.0", | ||||
|                 "@angular/compiler-cli": "^14.0.0", | ||||
|                 "@types/jasmine": "~4.0.0", | ||||
|                 "@types/node": "^18.8.3", | ||||
|                 "@types/node": "^18.11.9", | ||||
|                 "jasmine-core": "~4.1.0", | ||||
|                 "karma": "~6.3.0", | ||||
|                 "karma-chrome-launcher": "~3.1.0", | ||||
|                 "karma-coverage": "~2.2.0", | ||||
|                 "karma-jasmine": "~5.0.0", | ||||
|                 "karma-jasmine-html-reporter": "~1.7.0", | ||||
|                 "ts-node": "~8.3.0", | ||||
|                 "tslib": "^2.4.1", | ||||
|                 "typescript": "~4.7.2" | ||||
|             } | ||||
|         }, | ||||
| @@ -222,6 +221,12 @@ | ||||
|             "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", | ||||
|             "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": { | ||||
|             "version": "0.1402.6", | ||||
|             "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.6.tgz", | ||||
| @@ -3200,9 +3205,9 @@ | ||||
|             "dev": true | ||||
|         }, | ||||
|         "node_modules/@types/node": { | ||||
|             "version": "18.11.0", | ||||
|             "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", | ||||
|             "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", | ||||
|             "version": "18.11.9", | ||||
|             "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", | ||||
|             "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", | ||||
|             "dev": true | ||||
|         }, | ||||
|         "node_modules/@types/parse-json": { | ||||
| @@ -3705,12 +3710,6 @@ | ||||
|                 "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": { | ||||
|             "version": "1.0.10", | ||||
|             "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", | ||||
| @@ -4982,15 +4981,6 @@ | ||||
|             "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", | ||||
|             "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": { | ||||
|             "version": "3.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", | ||||
| @@ -7881,12 +7871,6 @@ | ||||
|                 "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": { | ||||
|             "version": "9.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", | ||||
| @@ -11730,32 +11714,10 @@ | ||||
|                 "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": { | ||||
|             "version": "2.4.0", | ||||
|             "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", | ||||
|             "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" | ||||
|             "version": "2.4.1", | ||||
|             "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", | ||||
|             "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" | ||||
|         }, | ||||
|         "node_modules/type-fest": { | ||||
|             "version": "0.21.3", | ||||
| @@ -12510,15 +12472,6 @@ | ||||
|                 "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": { | ||||
|             "version": "0.11.8", | ||||
|             "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", | ||||
| @@ -12659,6 +12612,12 @@ | ||||
|                             "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 | ||||
|         }, | ||||
|         "@types/node": { | ||||
|             "version": "18.11.0", | ||||
|             "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", | ||||
|             "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", | ||||
|             "version": "18.11.9", | ||||
|             "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", | ||||
|             "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", | ||||
|             "dev": true | ||||
|         }, | ||||
|         "@types/parse-json": { | ||||
| @@ -15153,12 +15112,6 @@ | ||||
|                 "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": { | ||||
|             "version": "1.0.10", | ||||
|             "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", | ||||
| @@ -16095,12 +16048,6 @@ | ||||
|             "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", | ||||
|             "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": { | ||||
|             "version": "3.0.1", | ||||
|             "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": { | ||||
|             "version": "9.1.0", | ||||
|             "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==", | ||||
|             "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": { | ||||
|             "version": "2.4.0", | ||||
|             "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", | ||||
|             "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" | ||||
|             "version": "2.4.1", | ||||
|             "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", | ||||
|             "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" | ||||
|         }, | ||||
|         "type-fest": { | ||||
|             "version": "0.21.3", | ||||
| @@ -21518,12 +21446,6 @@ | ||||
|             "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", | ||||
|             "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": { | ||||
|             "version": "0.11.8", | ||||
|             "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "kdb-web", | ||||
|     "version": "0.3.0", | ||||
|     "version": "0.3.dev128", | ||||
|     "scripts": { | ||||
|         "ng": "ng", | ||||
|         "update-version": "ts-node-esm update-version.ts", | ||||
| @@ -33,7 +33,6 @@ | ||||
|         "primeng": "^14.1.2", | ||||
|         "rxjs": "~7.5.0", | ||||
|         "socket.io-client": "^4.5.3", | ||||
|         "tslib": "^2.3.0", | ||||
|         "zone.js": "~0.11.4" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
| @@ -41,13 +40,14 @@ | ||||
|         "@angular/cli": "~14.0.0", | ||||
|         "@angular/compiler-cli": "^14.0.0", | ||||
|         "@types/jasmine": "~4.0.0", | ||||
|         "@types/node": "^18.8.3", | ||||
|         "@types/node": "^18.11.9", | ||||
|         "jasmine-core": "~4.1.0", | ||||
|         "karma": "~6.3.0", | ||||
|         "karma-chrome-launcher": "~3.1.0", | ||||
|         "karma-coverage": "~2.2.0", | ||||
|         "karma-jasmine": "~5.0.0", | ||||
|         "karma-jasmine-html-reporter": "~1.7.0", | ||||
|         "tslib": "^2.4.1", | ||||
|         "typescript": "~4.7.2" | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +1,65 @@ | ||||
| <section class="login-wrapper"> | ||||
|     <div class="login-form-wrapper"> | ||||
|         <div class="login-form"> | ||||
|             <form [formGroup]="loginForm"> | ||||
|                 <h1>{{'auth.header' | translate}}</h1> | ||||
|                 <div class="input-field"> | ||||
|                     <input type="email" pInputText formControlName="email" placeholder="{{'auth.login.e_mail' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|   <div class="login-form-wrapper"> | ||||
|     <div class="login-form"> | ||||
|       <form [formGroup]="loginForm"> | ||||
|         <h1>{{'auth.header' | translate}}</h1> | ||||
|         <div class="input-field"> | ||||
|           <input type="email" pInputText formControlName="email" placeholder="{{'auth.login.e_mail' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|                             (loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required) || | ||||
|                             (authUserAtrErrors.email.wrongData) || | ||||
|                             (authUserAtrErrors.email.notConfirmed) | ||||
|                         )}" autocomplete="username email"> | ||||
|                     <div *ngIf="submitted" class="invalid-feedback"> | ||||
|                         <div | ||||
|                             *ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required"> | ||||
|                             {{'auth.login.e_mail_required' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.login.user_not_found' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.email.notConfirmed">{{'auth.login.e_mail_not_confirmed' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="input-field"> | ||||
|                     <!-- | ||||
|                         !! WARNING !! | ||||
|                         Bugfix from https://github.com/primefaces/primeng/issues/10788 | ||||
|                         styleClass="p-password p-component p-inputwrapper p-input-icon-right" | ||||
|                         Remove after update! | ||||
|                     --> | ||||
|                     <p-password type="password" formControlName="password" placeholder="{{'auth.login.password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
|               *ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required"> | ||||
|               {{'auth.login.e_mail_required' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.login.user_not_found' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.email.notConfirmed">{{'auth.login.e_mail_not_confirmed' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="input-field"> | ||||
|           <!-- | ||||
|               !! WARNING !! | ||||
|               Bugfix from https://github.com/primefaces/primeng/issues/10788 | ||||
|               styleClass="p-password p-component p-inputwrapper p-input-icon-right" | ||||
|               Remove after update! | ||||
|           --> | ||||
|           <p-password type="password" formControlName="password" placeholder="{{'auth.login.password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|                             (loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required) || | ||||
|                             (authUserAtrErrors.password.wrongData) | ||||
|                         )}" autocomplete="current-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.login.password_required' | translate}}</div> | ||||
|                         <div *ngIf="authUserAtrErrors.password.wrongData">{{'auth.login.wrong_password' | translate}}</div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="login-form-submit"> | ||||
|                     <button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()" | ||||
|                         [disabled]="loginForm.invalid"></button> | ||||
|                 </div> | ||||
|                 <div class="login-form-sub-button-wrapper"> | ||||
|                     <div class="login-form-sub-btn-wrapper"> | ||||
|                         <button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn" | ||||
|                             (click)="register()"></button> | ||||
|                     </div> | ||||
|                     <div class="login-form-sub-btn-wrapper"> | ||||
|                         <button pButton label="{{'auth.login.forgot_password' | translate}}" | ||||
|                             class="btn login-form-sub-btn login-form-sub-login-btn p-button-text" | ||||
|                             (click)="forgotPassword()"></button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </form> | ||||
|                       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.login.password_required' | translate}}</div> | ||||
|             <div *ngIf="authUserAtrErrors.password.wrongData">{{'auth.login.wrong_password' | translate}}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="login-form-submit"> | ||||
|           <button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()" | ||||
|                   [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.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-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn" | ||||
|                     (click)="register()"></button> | ||||
|           </div> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.login.forgot_password' | translate}}" | ||||
|                     class="btn login-form-sub-btn login-form-sub-login-btn p-button-text" | ||||
|                     (click)="forgotPassword()"></button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </form> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
|     <app-auth-header></app-auth-header> | ||||
| </section> | ||||
|   <app-auth-header></app-auth-header> | ||||
| </section> | ||||
|   | ||||
| @@ -1,20 +1,21 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; | ||||
| import { AuthService } from 'src/app/services/auth/auth.service'; | ||||
| import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; | ||||
| import { Router } from '@angular/router'; | ||||
| import { catchError } from 'rxjs/operators'; | ||||
| import { ErrorDTO } from 'src/app/models/error/error-dto'; | ||||
| import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; | ||||
| import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; | ||||
| import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; | ||||
| import { SpinnerService } from 'src/app/services/spinner/spinner.service'; | ||||
| import { ThemeService } from 'src/app/services/theme/theme.service'; | ||||
| import { Component, OnInit } from "@angular/core"; | ||||
| import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; | ||||
| import { AuthService } from "src/app/services/auth/auth.service"; | ||||
| import { AuthUserDTO } from "src/app/models/auth/auth-user.dto"; | ||||
| import { ActivatedRoute, Router } from "@angular/router"; | ||||
| import { catchError } from "rxjs/operators"; | ||||
| import { ErrorDTO } from "src/app/models/error/error-dto"; | ||||
| import { AuthErrorMessages } from "src/app/models/auth/auth-error-messages.enum"; | ||||
| import { ServiceErrorCode } from "src/app/models/error/service-error-code.enum"; | ||||
| import { AuthUserAtrErrors } from "src/app/models/auth/auth-user-atr-errors"; | ||||
| import { SpinnerService } from "src/app/services/spinner/spinner.service"; | ||||
| import { ThemeService } from "src/app/services/theme/theme.service"; | ||||
| import { throwError } from "rxjs"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-login', | ||||
|   templateUrl: './login.component.html', | ||||
|   styleUrls: ['./login.component.scss'] | ||||
|   selector: "app-login", | ||||
|   templateUrl: "./login.component.html", | ||||
|   styleUrls: ["./login.component.scss"] | ||||
| }) | ||||
| export class LoginComponent implements OnInit { | ||||
|  | ||||
| @@ -25,45 +26,83 @@ export class LoginComponent implements OnInit { | ||||
|   submitted = false; | ||||
|  | ||||
|   authUserAtrErrors!: AuthUserAtrErrors; | ||||
|   code!: string; | ||||
|   state!: string; | ||||
|   user!: AuthUserDTO; | ||||
|   oAuthId!: string; | ||||
|  | ||||
|   constructor( | ||||
|     private authService: AuthService, | ||||
|     private formBuilder: FormBuilder, | ||||
|     private router: Router, | ||||
|     private spinnerService: SpinnerService, | ||||
|     private themeService: ThemeService | ||||
|   ) { } | ||||
|     private themeService: ThemeService, | ||||
|     private route: ActivatedRoute | ||||
|   ) { | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.spinnerService.showSpinner(); | ||||
|     this.authService.isUserLoggedInAsync().then(result => { | ||||
|       if (result) { | ||||
|         this.router.navigate(['/dashboard']); | ||||
|         this.router.navigate(["/dashboard"]); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       this.checkDiscordLogin(); | ||||
|       this.initLoginForm(); | ||||
|       this.resetStateFlags(); | ||||
|       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 { | ||||
|     this.authUserAtrErrors = new AuthUserAtrErrors(); | ||||
|   } | ||||
|  | ||||
|   initLoginForm(): void { | ||||
|     this.loginForm = this.formBuilder.group({ | ||||
|       email: ['', [Validators.required, Validators.email]], | ||||
|       password: ['', [Validators.required, Validators.minLength(8)]] | ||||
|       email: ["", [Validators.required, Validators.email]], | ||||
|       password: ["", [Validators.required, Validators.minLength(8)]] | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   register(): void { | ||||
|     this.router.navigate(['/auth/register']); | ||||
|     this.router.navigate(["/auth/register"]); | ||||
|   } | ||||
|  | ||||
|   forgotPassword(): void { | ||||
|     this.router.navigate(['/auth/forgot-password']); | ||||
|     this.router.navigate(["/auth/forgot-password"]); | ||||
|   } | ||||
|  | ||||
|   login(): void { | ||||
| @@ -76,8 +115,8 @@ export class LoginComponent implements OnInit { | ||||
|  | ||||
|     this.spinnerService.showSpinner(); | ||||
|     const user: AuthUserDTO = { | ||||
|       firstName: '', | ||||
|       lastName: '', | ||||
|       firstName: "", | ||||
|       lastName: "", | ||||
|       email: this.loginForm.value.email ?? null, | ||||
|       password: this.loginForm.value.password ?? null | ||||
|     }; | ||||
| @@ -107,8 +146,14 @@ export class LoginComponent implements OnInit { | ||||
|         this.themeService.loadTheme(); | ||||
|         this.themeService.loadMenu(); | ||||
|         this.spinnerService.hideSpinner(); | ||||
|         this.router.navigate(['/dashboard']); | ||||
|         this.router.navigate(["/dashboard"]); | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   discordLogin() { | ||||
|     this.authService.getDiscordAuthURL().subscribe(url => { | ||||
|       window.location.href = url.loginUrl; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -72,12 +72,6 @@ | ||||
|                   [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> | ||||
|   | ||||
| @@ -34,14 +34,6 @@ export class RegistrationComponent implements OnInit { | ||||
|     password: false | ||||
|   }; | ||||
|  | ||||
|   showEMailConfirmation = false; | ||||
|   showEMailConfirmationError = false; | ||||
|  | ||||
|   code!: string; | ||||
|   state!: string; | ||||
|   user!: AuthUserDTO; | ||||
|   oAuthId!: string; | ||||
|  | ||||
|   constructor( | ||||
|     private authService: AuthService, | ||||
|     private formBuilder: FormBuilder, | ||||
| @@ -62,48 +54,7 @@ export class RegistrationComponent implements OnInit { | ||||
|     this.confirmEMail(); | ||||
|     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(); | ||||
|       } | ||||
|     ); | ||||
|     this.initData(); | ||||
|   } | ||||
|  | ||||
|   initData() { | ||||
| @@ -126,18 +77,13 @@ export class RegistrationComponent implements OnInit { | ||||
|  | ||||
|   initLoginForm(): void { | ||||
|     this.loginForm = this.formBuilder.group({ | ||||
|       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)]] | ||||
|       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)]] | ||||
|     }); | ||||
|  | ||||
|     if (this.user) { | ||||
|       this.loginForm.controls.email.disable(); | ||||
|       this.loginForm.controls.emailRepeat.disable(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   register(): void { | ||||
| @@ -160,42 +106,10 @@ 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, | ||||
| @@ -237,10 +151,4 @@ export class RegistrationComponent implements OnInit { | ||||
|         }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   discordLogin() { | ||||
|     this.authService.getDiscordAuthURL().subscribe(url => { | ||||
|       window.location.href = url.loginUrl; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -167,6 +167,7 @@ export class AuthService { | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   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({ | ||||
| @@ -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= | ||||
|   discordRegister(oAuthDTO: OAuthDTO) { | ||||
|     return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|     "WebVersion": { | ||||
|         "Major": "0", | ||||
|         "Minor": "3", | ||||
|         "Micro": "dev70" | ||||
|         "Micro": "dev128" | ||||
|     }, | ||||
|     "Themes": [ | ||||
|         { | ||||
|   | ||||
| @@ -93,6 +93,7 @@ | ||||
|       "e_mail": "E-Mail", | ||||
|       "password": "Passwort", | ||||
|       "login": "Einloggen", | ||||
|       "login_with_discord": "Mit Discord Einloggen", | ||||
|       "register": "Registrieren", | ||||
|       "forgot_password": "Passwort vergessen?", | ||||
|       "e_mail_required": "E-Mail benötigt", | ||||
|   | ||||
| @@ -373,7 +373,7 @@ footer { | ||||
|     .login-form-wrapper, | ||||
|     .auth-header { | ||||
|         width: 350px; | ||||
|         height: 350px; | ||||
|         height: 450px; | ||||
|  | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user