Added authentication with Firebase

This commit is contained in:
Jim Martens 2021-09-18 20:16:45 +02:00
parent 64626a9851
commit f9fb93a57c
25 changed files with 375 additions and 7 deletions

View File

@ -0,0 +1,20 @@
<header>
<app-navbar [currentPage]="'administration'"></app-navbar>
</header>
<div class="container">
<div class="row">
<div class="col">
<h1>Administration</h1>
<a [routerLink]="'factions'">Fraktionen</a>
</div>
</div>
<div class="row">
<div class="col">
<router-outlet></router-outlet>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdministrationComponent } from './administration.component';
describe('AdministrationComponent', () => {
let component: AdministrationComponent;
let fixture: ComponentFixture<AdministrationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdministrationComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AdministrationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-administration',
templateUrl: './administration.component.html',
styleUrls: ['./administration.component.scss']
})
export class AdministrationComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,4 @@
export interface Faction {
name: string;
size: number;
}

View File

@ -0,0 +1,16 @@
<table class="table">
<thead>
<tr>
<th>Fraktion</th>
<th># Mitglieder</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let faction of factions">
<td>{{faction.name}}</td>
<td>{{faction.size}}</td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FactionsComponent } from './factions.component';
describe('FactionsComponent', () => {
let component: FactionsComponent;
let fixture: ComponentFixture<FactionsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FactionsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FactionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,30 @@
import { Component, OnInit } from '@angular/core';
import {Faction} from './faction';
import {FirebaseService} from '../../../firebase/firebase.service';
@Component({
selector: 'app-factions',
templateUrl: './factions.component.html',
styleUrls: ['./factions.component.scss']
})
export class FactionsComponent implements OnInit {
public factions: Faction[] = [];
constructor(private firebase: FirebaseService) { }
ngOnInit(): void {
const factionRef = this.firebase.getReference('factions')
this.firebase.registerListener(factionRef, (factionData: Faction[]) => {
this.factions = factionData;
this.factions.sort((factionA, factionB) => {
if (factionA.size < factionB.size) {
return 1;
}
if (factionA.size > factionB.size) {
return -1;
}
return 0;
})
});
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuard', () => {
let guard: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
guard = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree} from '@angular/router';
import {Observable} from 'rxjs';
import {AuthService} from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.auth.isLoggedIn();
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,43 @@
import {Injectable} from '@angular/core';
import {FirebaseService} from '../firebase/firebase.service';
import {User, UserCredential} from 'firebase/auth';
import {Router} from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private currentUser: User | null = null;
constructor(private firebase: FirebaseService,
private router: Router) {
}
public getUser(): User|null {
return this.currentUser;
}
public isLoggedIn(): boolean {
return this.currentUser != null;
}
public login(email: string, password: string, redirectUrl: string) {
this.firebase.signIn(email, password)
.then((userCredential: UserCredential) => {
this.currentUser = userCredential.user;
this.router.navigateByUrl(redirectUrl);
})
.catch((error) => {
console.error(error.message());
});
}
public logout(redirectUrl: string) {
this.firebase.signOutCurrentUser()
.then(() => {
this.currentUser = null;
this.router.navigateByUrl(redirectUrl);
});
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { FirebaseService } from './firebase.service';
describe('FirebaseService', () => {
let service: FirebaseService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(FirebaseService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
<header>
<app-navbar [currentPage]="'login'"></app-navbar>
</header>
<div class="container">
<h1>Login</h1>
<div class="row">
<div class="col">
<form>
<div class="mb-3">
<label for="email" class="form-label">E-Mail-Adresse</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" #email>
<div id="emailHelp" class="form-text">E-Mail wird nicht weitergegeben</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">Passwort</label>
<input type="password" class="form-control" id="password" #password>
</div>
<button type="button" class="btn btn-primary" (click)="login(email.value, password.value)">Login</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import {Component, OnInit} from '@angular/core';
import {AuthService} from '../auth/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
constructor(private auth: AuthService) {
}
ngOnInit(): void {
}
public login(email: string, password: string) {
this.auth.login(email, password, '/administration');
}
}

View File

@ -0,0 +1 @@
<p>logout works!</p>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LogoutComponent } from './logout.component';
describe('LogoutComponent', () => {
let component: LogoutComponent;
let fixture: ComponentFixture<LogoutComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LogoutComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LogoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import { Component, OnInit } from '@angular/core';
import {AuthService} from '../auth/auth.service';
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.scss']
})
export class LogoutComponent implements OnInit {
constructor(private auth: AuthService) { }
ngOnInit(): void {
this.auth.logout('/');
}
}

View File

@ -2,10 +2,20 @@
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'statistics' ? 'page' : 'false'" routerLink="/statistics" routerLinkActive="active">Statistics</a>
</li>
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'edit' ? 'page' : 'false'" routerLink="/edit" routerLinkActive="active">Edit</a>
</li>
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'administration' ? 'page' : 'false'" routerLink="/administration" routerLinkActive="active">Administration</a>
</li>
<ng-container *ngIf="auth.isLoggedIn(); else loggedOut">
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'edit' ? 'page' : 'false'" routerLink="/edit" routerLinkActive="active">Edit</a>
</li>
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'administration' ? 'page' : 'false'" routerLink="/administration" routerLinkActive="active">Administration</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/logout">Logout</a>
</li>
</ng-container>
<ng-template #loggedOut>
<li class="nav-item">
<a class="nav-link" [attr.aria-current]="currentPage === 'login' ? 'page' : 'false'" routerLink="/login" routerLinkActive="active">Login</a>
</li>
</ng-template>
</ul>

View File

@ -1,4 +1,5 @@
import {Component, Input, OnInit} from '@angular/core';
import {AuthService} from '../auth/auth.service';
@Component({
selector: 'app-navbar',
@ -9,7 +10,7 @@ export class NavbarComponent implements OnInit {
@Input() currentPage: string = '';
constructor() { }
constructor(public auth: AuthService) { }
ngOnInit(): void {
}