Merge pull request 'SES-89 Connected to backend for login' (#28) from SES-89 into master

Reviewed-on: #28
This commit is contained in:
Natalia Gawron 2020-12-13 13:29:18 +01:00
commit 73f01e8e2c
10 changed files with 128 additions and 25 deletions

View File

@ -3,6 +3,7 @@ import { SelectRoleComponent } from './app/components/select-role/select-role.co
import { SignInComponent } from './app/components/sign-in/sign-in.component'; import { SignInComponent } from './app/components/sign-in/sign-in.component';
import { RegistrationComponent } from './app/components/registration/registration.component'; import { RegistrationComponent } from './app/components/registration/registration.component';
import {GameMasterDashboardComponent} from './app/components/game-master-dashboard/game-master-dashboard.component'; import {GameMasterDashboardComponent} from './app/components/game-master-dashboard/game-master-dashboard.component';
import {PlayerDashboardComponent} from './app/components/player-dashboard/player-dashboard.component';
const routes: Routes = [ const routes: Routes = [
{ {
@ -24,6 +25,11 @@ const routes: Routes = [
path: 'gamemaster', path: 'gamemaster',
component: GameMasterDashboardComponent, component: GameMasterDashboardComponent,
pathMatch: 'full' pathMatch: 'full'
},
{
path: 'player',
component: PlayerDashboardComponent,
pathMatch: 'full'
} }
]; ];

View File

@ -9,6 +9,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SignInComponent } from './components/sign-in/sign-in.component'; import { SignInComponent } from './components/sign-in/sign-in.component';
import { RegistrationComponent } from './components/registration/registration.component'; import { RegistrationComponent } from './components/registration/registration.component';
import { GameMasterDashboardComponent} from './components/game-master-dashboard/game-master-dashboard.component'; import { GameMasterDashboardComponent} from './components/game-master-dashboard/game-master-dashboard.component';
import {PlayerDashboardComponent} from './components/player-dashboard/player-dashboard.component';
import { import {
MatCardModule, MatCardModule,
MatTabsModule, MatTabsModule,
@ -18,6 +19,7 @@ import {
MatCheckboxModule, MatCheckboxModule,
MatIconModule, MatSidenavModule, MatToolbarModule, MatListModule MatIconModule, MatSidenavModule, MatToolbarModule, MatListModule
} from '@angular/material'; } from '@angular/material';
import {UserService} from '../services/user.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -26,6 +28,7 @@ import {
SignInComponent, SignInComponent,
RegistrationComponent, RegistrationComponent,
GameMasterDashboardComponent, GameMasterDashboardComponent,
PlayerDashboardComponent
], ],
imports: [ imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
@ -45,7 +48,9 @@ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
MatToolbarModule, MatToolbarModule,
MatListModule, MatListModule,
], ],
providers: [], providers: [
UserService
],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View File

@ -2,11 +2,11 @@
<div formGroupName="newAccount" class="container"> <div formGroupName="newAccount" class="container">
<mat-icon matSuffix class="arrow-back" (click)="GoToLoginPage()">arrow_back</mat-icon> <mat-icon matSuffix class="arrow-back" (click)="GoToLoginPage()">arrow_back</mat-icon>
<div class="primary-text header">Create an Account</div> <div class="primary-text header">Create an Account</div>
<mat-form-field class="form-container"> <mat-form-field class="form-container">
<input <input
matInput matInput
formControlName="username" formControlName="username"
placeholder="Username" placeholder="Username"
type="text" type="text"
required required
@ -18,9 +18,9 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-container"> <mat-form-field class="form-container">
<input <input
matInput matInput
formControlName="password" formControlName="password"
required required
placeholder="Password" placeholder="Password"
type="password" type="password"
@ -32,10 +32,10 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-container"> <mat-form-field class="form-container">
<input <input
matInput matInput
formControlName="confirmPassword" formControlName="confirmPassword"
required required
placeholder="Confirm Password" placeholder="Confirm Password"
type="password" type="password"
name="confirmPassword"/> name="confirmPassword"/>
@ -55,4 +55,4 @@
<mat-icon matSuffix class="arrow-forward">arrow_forward</mat-icon> <mat-icon matSuffix class="arrow-forward">arrow_forward</mat-icon>
</button> </button>
</div> </div>
</div> </div>

View File

@ -6,7 +6,7 @@
<mat-form-field class="form-container"> <mat-form-field class="form-container">
<input <input
matInput matInput
formControlName="username" formControlName="username"
placeholder="Username" placeholder="Username"
type="text" type="text"
required required
@ -18,9 +18,9 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-container"> <mat-form-field class="form-container">
<input <input
matInput matInput
formControlName="password" formControlName="password"
required required
placeholder="Password" placeholder="Password"
type="password" type="password"
@ -31,6 +31,9 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-error *ngIf="apiError">
{{apiErrorMessage}}
</mat-error>
<button <button
mat-raised-button mat-raised-button
class="btn-primary form-container" class="btn-primary form-container"

View File

@ -1,16 +1,23 @@
import { Component } from '@angular/core'; import { Component, OnDestroy } from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms'; import { FormGroup, Validators, FormBuilder } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import {UserService} from '../../../services/user.service';
import {ErrorResponse} from '../../../types/ErrorResponse';
import {Subscription} from 'rxjs';
@Component({ @Component({
selector: 'app-sign-in', selector: 'app-sign-in',
templateUrl: './sign-in.component.html', templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.css'] styleUrls: ['./sign-in.component.css']
}) })
export class SignInComponent { export class SignInComponent implements OnDestroy {
isExpanded = false; allSubscriptions = new Subscription();
constructor(private router: Router, private formBuilder: FormBuilder) {} isExpanded = false;
apiError = false;
apiErrorMessage = '';
constructor(private router: Router, private formBuilder: FormBuilder, private userService: UserService) {}
public signInFormGroup: FormGroup = this.formBuilder.group({ public signInFormGroup: FormGroup = this.formBuilder.group({
signIn: this.formBuilder.group({ signIn: this.formBuilder.group({
@ -21,8 +28,19 @@ export class SignInComponent {
}) })
}); });
onLoginButtonClick(){ onLoginButtonClick() {
//TODO connect with backend and added router this.allSubscriptions.add(
this.userService.tryLogin(
this.signInFormGroup.get('signIn').value['username'],
this.signInFormGroup.get('signIn').value['password']).subscribe(
(success) => {
this.router.navigate(['player']);
},
(error: ErrorResponse) => {
this.apiError = true;
this.apiErrorMessage = error.message;
}
));
} }
onRegisterButtonClick(){ onRegisterButtonClick(){
@ -41,4 +59,8 @@ export class SignInComponent {
toggle() { toggle() {
this.isExpanded = !this.isExpanded; this.isExpanded = !this.isExpanded;
} }
ngOnDestroy() {
this.allSubscriptions.unsubscribe();
}
} }

View File

@ -0,0 +1,31 @@
import {Inject, Injectable} from '@angular/core';
import {HttpClient, HttpParams} from '@angular/common/http';
import {Observable, of, throwError} from 'rxjs';
import {ErrorResponse} from '../types/ErrorResponse';
import {Either} from '../types/Either';
import {switchMap} from 'rxjs/operators';
Injectable({
providedIn: 'root'
})
export class UserService {
private baseUrl = 'api/user/';
constructor(private http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
this.baseUrl = baseUrl + this.baseUrl;
}
tryLogin(login: string, password: string): Observable<number> {
const params = new HttpParams()
.set('userName', login)
.set('password', password);
return this.http.get<Either<number, ErrorResponse>>(this.baseUrl + 'login', { params }).pipe(
switchMap(response => {
if (response.isLeft) {
return of(response.left);
} else {
return throwError(response.right);
}
})
);
}
}

View File

@ -0,0 +1,5 @@
export interface Either<TL, TR> {
left: TL;
right: TR;
isLeft: boolean;
}

View File

@ -0,0 +1,4 @@
export interface ErrorResponse {
code: number;
message: string;
}

View File

@ -4,6 +4,10 @@ using System.Threading.Tasks;
namespace SessionCompanion.Controllers namespace SessionCompanion.Controllers
{ {
using SessionCompanion.Extensions.EitherType;
using SessionCompanion.ViewModels.ApiResponses;
using SessionCompanion.ViewModels.UserViewModels;
[Route("api/user")] [Route("api/user")]
[ApiController] [ApiController]
public class UserController : Controller public class UserController : Controller
@ -15,12 +19,27 @@ namespace SessionCompanion.Controllers
this._service = service; this._service = service;
} }
/// <summary>
/// Metoda przyjmuje login oraz hasło i sprawdza czy istnieje użytkownik o podanych parametrach
/// </summary>
/// <param name="userName"> Nazwa użytkownika </param>
/// <param name="password"> Hasło </param>
/// <returns>Id użytkownika lub wiadomość błędu</returns>
[HttpGet("login")] [HttpGet("login")]
public async Task<IActionResult> Login(string userName, string password) public async Task<Either<int, ErrorResponse>> Login(string userName, string password)
{ {
var User = await _service.SearchUserByNickname(userName); UserViewModel user = await _service.SearchUserByNickname(userName);
if (User.Password == password) { return Json(User.Id); }
return BadRequest(); if (user != null && user.Password.Equals(password))
{
return user.Id;
}
return new ErrorResponse()
{
StatusCode = 403,
Message = "User name not found or incorrect password"
};
} }
} }
} }

View File

@ -11,6 +11,14 @@
<param name="id">Identyfikator postaci</param> <param name="id">Identyfikator postaci</param>
<returns>ViewModel Postaci</returns> <returns>ViewModel Postaci</returns>
</member> </member>
<member name="M:SessionCompanion.Controllers.UserController.Login(System.String,System.String)">
<summary>
Metoda przyjmuje login oraz hasło i sprawdza czy istnieje użytkownik o podanych parametrach
</summary>
<param name="userName"> Nazwa użytkownika </param>
<param name="password"> Hasło </param>
<returns>Id użytkownika lub wiadomość błędu</returns>
</member>
<member name="F:SessionCompanion.Hubs.SessionHub.ConnectedCharacters"> <member name="F:SessionCompanion.Hubs.SessionHub.ConnectedCharacters">
<summary> <summary>
Lista zalogowanych graczy i identyfikator wybranej postaci Lista zalogowanych graczy i identyfikator wybranej postaci