Structural changes:
- AuthenticationService->AuthService - removed underscore-directories - put site related stuff into site/ - same for projector - auth service went into a core/ directory, used by site and projector - the alert is now not global anymore. Every view can have its own alert - make the auth service query users/whoami for the current user - made a new OpenSlides service for managing the startup ... A lot todo ...
This commit is contained in:
parent
ed2e44b484
commit
3f78ba1f3d
@ -3,6 +3,14 @@
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/users/logout": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/users/whoami": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/rest": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
|
@ -1,4 +0,0 @@
|
||||
<div *ngFor="let alert of alerts" class="{{ cssClass(alert) }} alert-dismissable">
|
||||
{{alert.message}}
|
||||
<a class="close" (click)="removeAlert(alert)">×</a>
|
||||
</div>
|
@ -1,51 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { Alert, AlertType } from '../../_models/alert';
|
||||
import { AlertService } from '../../_services/alert.service';
|
||||
|
||||
@Component({
|
||||
selector: 'alert',
|
||||
templateUrl: './alert.component.html',
|
||||
styleUrls: ['./alert.component.css']
|
||||
})
|
||||
export class AlertComponent implements OnInit {
|
||||
alerts: Alert[] = [];
|
||||
|
||||
constructor(private alertService: AlertService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.alertService.getAlert().subscribe((alert: Alert) => {
|
||||
if (!alert) {
|
||||
// clear alerts when an empty alert is received
|
||||
this.alerts = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// add alert to array
|
||||
this.alerts.push(alert);
|
||||
});
|
||||
}
|
||||
|
||||
removeAlert(alert: Alert) {
|
||||
this.alerts = this.alerts.filter(x => x !== alert);
|
||||
}
|
||||
|
||||
cssClass(alert: Alert) {
|
||||
if (!alert) {
|
||||
return;
|
||||
}
|
||||
|
||||
// return css class based on alert type
|
||||
switch (alert.type) {
|
||||
case AlertType.Success:
|
||||
return 'alert alert-success';
|
||||
case AlertType.Error:
|
||||
return 'alert alert-danger';
|
||||
case AlertType.Info:
|
||||
return 'alert alert-info';
|
||||
case AlertType.Warning:
|
||||
return 'alert alert-warning';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
import { Alert, AlertType } from '../_models/alert';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AlertService {
|
||||
private subject = new Subject<Alert>();
|
||||
|
||||
constructor() { }
|
||||
|
||||
getAlert(): Observable<any> {
|
||||
return this.subject.asObservable();
|
||||
}
|
||||
|
||||
success(message: string) {
|
||||
this.alert(AlertType.Success, message);
|
||||
}
|
||||
|
||||
error(message: string) {
|
||||
this.alert(AlertType.Error, message);
|
||||
}
|
||||
|
||||
info(message: string) {
|
||||
this.alert(AlertType.Info, message);
|
||||
}
|
||||
|
||||
warn(message: string) {
|
||||
this.alert(AlertType.Warning, message);
|
||||
}
|
||||
|
||||
alert(type: AlertType, message: string) {
|
||||
this.subject.next(<Alert>{ type: type, message: message });
|
||||
}
|
||||
|
||||
clear() {
|
||||
// clear alerts
|
||||
this.subject.next();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
CanActivate, Router,
|
||||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot
|
||||
} from '@angular/router';
|
||||
|
||||
import { AuthenticationService } from "./authentication.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthGuard implements CanActivate {
|
||||
|
||||
constructor(private authenticationService: AuthenticationService, private router: Router) { }
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
console.log('AuthGuard#canActivate called');
|
||||
let url: string = state.url;
|
||||
|
||||
return this.checkLogin(url);
|
||||
}
|
||||
|
||||
checkLogin(url: string): boolean {
|
||||
if (this.authenticationService.isLoggedIn) { return true; }
|
||||
|
||||
// Store the attempted URL for redirecting
|
||||
this.authenticationService.redirectUrl = url;
|
||||
|
||||
// Navigate to the login page with extras
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpClient, HttpResponse,
|
||||
HttpErrorResponse, HttpHeaders
|
||||
} from '@angular/common/http';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, map, tap, delay } from 'rxjs/operators';
|
||||
|
||||
import { User } from '../users/user';
|
||||
|
||||
const httpOptions = {
|
||||
withCredentials: true,
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
};
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthenticationService {
|
||||
isLoggedIn: boolean;
|
||||
loginURL: string = '/users/login/'
|
||||
|
||||
// store the URL so we can redirect after logging in
|
||||
redirectUrl: string;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
|
||||
//check for the cookie in local storrage
|
||||
//TODO checks for username now since django does not seem to return a cookie
|
||||
if(localStorage.getItem("username")) {
|
||||
this.isLoggedIn = true;
|
||||
} else {
|
||||
this.isLoggedIn = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//loggins a users. expects a user model
|
||||
loginUser(user: User): Observable<any> {
|
||||
return this.http.post(this.loginURL, user, httpOptions)
|
||||
.pipe(
|
||||
tap(val => {
|
||||
this.isLoggedIn = true;
|
||||
//Set the session cookie in local storrage.
|
||||
//TODO needs validation
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//logout the user
|
||||
//TODO not yet used
|
||||
logoutUser(): void {
|
||||
this.isLoggedIn = false;
|
||||
localStorage.removeItem("username");
|
||||
}
|
||||
|
||||
//very generic error handling function.
|
||||
//implicitly returns an observable that will display an error message
|
||||
private handleError<T>() {
|
||||
return (error: any): Observable<T> => {
|
||||
console.error(error);
|
||||
return of(error);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,21 +1,17 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BaseComponent } from '../base.component';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TitleService } from '../core/title.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-agenda',
|
||||
templateUrl: './agenda.component.html',
|
||||
styleUrls: ['./agenda.component.css']
|
||||
})
|
||||
export class AgendaComponent extends BaseComponent implements OnInit {
|
||||
export class AgendaComponent implements OnInit {
|
||||
|
||||
constructor(titleService: Title) {
|
||||
super(titleService)
|
||||
constructor(private titleService: TitleService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//TODO translate
|
||||
super.setTitle("Agenda");
|
||||
this.titleService.setTitle("Agenda");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,33 +1,37 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { ProjectorComponent } from "./projector/projector.component";
|
||||
import { StartComponent } from "./start/start.component";
|
||||
import { ProjectorContainerComponent } from "./projector/projector-container.component";
|
||||
import { StartComponent } from "./site/start.component";
|
||||
import { AgendaComponent } from "./agenda/agenda.component";
|
||||
import { MotionsComponent } from "./motions/motions.component";
|
||||
import { SiteComponent } from "./site/site.component";
|
||||
import { LoginComponent } from './users/login.component';
|
||||
|
||||
import { AuthGuard } from "./_services/auth-guard.service";
|
||||
import { RouterAuthGuard } from "./core/router-auth-guard.service";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'projector', component: ProjectorComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{
|
||||
path: '',
|
||||
component: SiteComponent,
|
||||
canActivate: [AuthGuard],
|
||||
children: [
|
||||
{ path: '', component: StartComponent },
|
||||
{ path: 'agenda', component: AgendaComponent },
|
||||
{ path: 'motions', component: MotionsComponent },
|
||||
]
|
||||
},
|
||||
{ path: '**', redirectTo: '' },
|
||||
{ path: 'projector/:id', component: ProjectorComponent },
|
||||
//{ path: 'projector', redirect: 'projector/1' }, // Test this
|
||||
{ path: 'real-projector/:id', component: ProjectorContainerComponent },
|
||||
//{ path: 'real-projector', redirect: 'real-projector/1' }, // this too
|
||||
{
|
||||
path: '',
|
||||
component: SiteComponent,
|
||||
canActivate: [RouterAuthGuard],
|
||||
children: [
|
||||
{ path: '', component: StartComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'agenda', component: AgendaComponent },
|
||||
{ path: 'motions', component: MotionsComponent },
|
||||
]
|
||||
},
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
@ -1,2 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { OpenSlidesService } from './core/openslides.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'OpenSlides 3';
|
||||
constructor() { }
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(private openSlides: OpenSlidesService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.openSlides.bootup();
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,17 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { fas } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { LoginComponent } from './users/login.component';
|
||||
import { UsersComponent } from './users/users.component';
|
||||
import { AppRoutingModule } from './/app-routing.module';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { ProjectorComponent } from './projector/projector.component';
|
||||
import { ProjectorContainerComponent } from './projector/projector-container.component';
|
||||
import { MotionsComponent } from './motions/motions.component';
|
||||
import { AgendaComponent } from './agenda/agenda.component';
|
||||
import { SiteComponent } from './site/site.component';
|
||||
import { StartComponent } from './start/start.component';
|
||||
import { AlertComponent } from './_directives/alert/alert.component';
|
||||
import { AlertService } from './_services/alert.service';
|
||||
import { StartComponent } from './site/start.component';
|
||||
import { AlertComponent } from './site/alert.component';
|
||||
import { AlertService } from './site/alert.service';
|
||||
|
||||
//add font-awesome icons to library.
|
||||
//will blow up the code.
|
||||
@ -28,6 +29,7 @@ library.add(fas);
|
||||
LoginComponent,
|
||||
UsersComponent,
|
||||
ProjectorComponent,
|
||||
ProjectorContainerComponent,
|
||||
MotionsComponent,
|
||||
AgendaComponent,
|
||||
SiteComponent,
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
//provides functions that might be used by a lot of components
|
||||
export abstract class BaseComponent {
|
||||
private titleSuffix: string = " - OpenSlides 3";
|
||||
|
||||
constructor(protected titleService: Title) { }
|
||||
|
||||
setTitle(prefix: string) {
|
||||
this.titleService.setTitle( prefix + this.titleSuffix );
|
||||
}
|
||||
|
||||
}
|
81
client/src/app/core/auth.service.ts
Normal file
81
client/src/app/core/auth.service.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpClient,
|
||||
HttpResponse,
|
||||
HttpErrorResponse,
|
||||
HttpHeaders
|
||||
} from '@angular/common/http';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, map, tap, delay } from 'rxjs/operators';
|
||||
|
||||
import { User } from '../users/user';
|
||||
|
||||
const httpOptions = {
|
||||
withCredentials: true,
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
};
|
||||
|
||||
export interface LoginResponse {
|
||||
user_id: number;
|
||||
user: User;
|
||||
}
|
||||
|
||||
export interface WhoAmIResponse extends LoginResponse {
|
||||
guest_enabled: boolean;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
isLoggedIn: boolean = false;
|
||||
|
||||
// store the URL so we can redirect after logging in
|
||||
redirectUrl: string;
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
// Initialize the service by querying the server
|
||||
init(): Observable<WhoAmIResponse | {}> {
|
||||
return this.http.get<WhoAmIResponse>('users/whoami', httpOptions)
|
||||
.pipe(
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
loginUser(user: User): Observable<LoginResponse | {}> {
|
||||
return this.http.post<LoginResponse>('users/login', user, httpOptions)
|
||||
.pipe(
|
||||
tap(val => {
|
||||
console.log(val)
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
//logout the user
|
||||
//TODO reboot openslides
|
||||
logout(): any {
|
||||
console.log("logout");
|
||||
// TODO Why isn't the request send??
|
||||
let t = this.http.post('users/logout', undefined, httpOptions);
|
||||
/*.pipe(
|
||||
tap(val => {
|
||||
console.log(val)
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
);*/
|
||||
console.log(t);
|
||||
}
|
||||
|
||||
//very generic error handling function.
|
||||
//implicitly returns an observable that will display an error message
|
||||
private handleError<T>() {
|
||||
return (error: any): Observable<T> => {
|
||||
console.error(error);
|
||||
return of(error);
|
||||
}
|
||||
};
|
||||
}
|
24
client/src/app/core/openslides.service.ts
Normal file
24
client/src/app/core/openslides.service.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { AuthService, WhoAmIResponse } from './auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OpenSlidesService {
|
||||
|
||||
constructor(private auth: AuthService, private router: Router) { }
|
||||
|
||||
bootup () {
|
||||
// TODO Lock the interface..
|
||||
this.auth.init().subscribe((whoami: WhoAmIResponse) => {
|
||||
console.log(whoami);
|
||||
if (!whoami.user && !whoami.guest_enabled) {
|
||||
this.router.navigate(['/login']);
|
||||
} else {
|
||||
// It's ok!
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
40
client/src/app/core/router-auth-guard.service.ts
Normal file
40
client/src/app/core/router-auth-guard.service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
CanActivate,
|
||||
Router,
|
||||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot
|
||||
} from '@angular/router';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class RouterAuthGuard implements CanActivate {
|
||||
|
||||
constructor(private authService: AuthService, private router: Router) { }
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
return this.checkAccess(state.url);
|
||||
}
|
||||
|
||||
checkAccess(url: string): boolean {
|
||||
if (url === '/login') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check base permission for the current state
|
||||
let hasBasePermission = true; // TODO: get this from the current state...
|
||||
|
||||
if (!hasBasePermission) {
|
||||
// Store the attempted URL for redirecting
|
||||
this.authService.redirectUrl = url;
|
||||
|
||||
// Navigate to the login page with extras
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
16
client/src/app/core/title.service.ts
Normal file
16
client/src/app/core/title.service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
// Provides functionallity to set the webpage title
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TitleService {
|
||||
private titleSuffix: string = " - OpenSlides 3";
|
||||
|
||||
constructor(protected titleService: Title) { }
|
||||
|
||||
setTitle(prefix: string) {
|
||||
this.titleService.setTitle(prefix + this.titleSuffix);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { BaseComponent } from '../base.component';
|
||||
import { User } from '../users/user';
|
||||
import { AuthenticationService } from '../_services/authentication.service';
|
||||
import { AlertService } from '../_services/alert.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.css']
|
||||
})
|
||||
export class LoginComponent extends BaseComponent implements OnInit {
|
||||
user: User = {
|
||||
username: '',
|
||||
password: ''
|
||||
};
|
||||
info: string;
|
||||
|
||||
constructor(
|
||||
titleService: Title,
|
||||
private authenticationService: AuthenticationService,
|
||||
private alertService: AlertService,
|
||||
private router: Router,
|
||||
) {
|
||||
super(titleService);
|
||||
this.setInfo();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//TODO translate
|
||||
super.setTitle("Anmelden");
|
||||
}
|
||||
|
||||
setInfo() {
|
||||
this.info = 'Logged in? ' + (this.authenticationService.isLoggedIn ? 'in' : 'out');
|
||||
}
|
||||
|
||||
//Todo: This serves as a prototype and need enhancement,
|
||||
//like saving a "logged in state" and real checking the server
|
||||
//if logIn was fine
|
||||
onSubmit() {
|
||||
this.authenticationService.loginUser(this.user).subscribe(
|
||||
res => {
|
||||
if (res.status === 400) {
|
||||
//TODO, add more errors here, use translation
|
||||
this.alertService.error("Benutzername oder Passwort war nicht korrekt.");
|
||||
} else {
|
||||
this.alertService.success("Logged in! :)");
|
||||
this.setInfo();
|
||||
if (this.authenticationService.isLoggedIn) {
|
||||
localStorage.setItem("username", res.user.username);
|
||||
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
let redirect = this.authenticationService.redirectUrl ?
|
||||
this.authenticationService.redirectUrl : '/';
|
||||
|
||||
// Redirect the user
|
||||
this.router.navigate([redirect]);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,20 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BaseComponent } from '../base.component';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TitleService } from '../core/title.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-motions',
|
||||
templateUrl: './motions.component.html',
|
||||
styleUrls: ['./motions.component.css']
|
||||
selector: 'app-motions',
|
||||
templateUrl: './motions.component.html',
|
||||
styleUrls: ['./motions.component.css']
|
||||
})
|
||||
export class MotionsComponent extends BaseComponent implements OnInit {
|
||||
export class MotionsComponent implements OnInit {
|
||||
|
||||
constructor(titleService: Title) {
|
||||
super(titleService)
|
||||
}
|
||||
constructor(private titleService: TitleService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.setTitle("Motions");
|
||||
}
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle("Motions");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
<p>
|
||||
projector container works!
|
||||
Here an iframe with the real-projector is needed
|
||||
</p>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProjectorContainerComponent } from './projector-container.component';
|
||||
|
||||
describe('ProjectorContainerComponent', () => {
|
||||
let component: ProjectorContainerComponent;
|
||||
let fixture: ComponentFixture<ProjectorContainerComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ProjectorContainerComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectorContainerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
18
client/src/app/projector/projector-container.component.ts
Normal file
18
client/src/app/projector/projector-container.component.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { TitleService } from '../core/title.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-projector-container',
|
||||
templateUrl: './projector-container.component.html',
|
||||
styleUrls: ['./projector-container.component.css']
|
||||
})
|
||||
export class ProjectorContainerComponent implements OnInit {
|
||||
|
||||
constructor(protected titleService: TitleService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('Projector');
|
||||
}
|
||||
|
||||
}
|
@ -3,23 +3,23 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ProjectorComponent } from './projector.component';
|
||||
|
||||
describe('ProjectorComponent', () => {
|
||||
let component: ProjectorComponent;
|
||||
let fixture: ComponentFixture<ProjectorComponent>;
|
||||
let component: ProjectorComponent;
|
||||
let fixture: ComponentFixture<ProjectorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ProjectorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ProjectorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BaseComponent } from '../base.component';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-projector',
|
||||
templateUrl: './projector.component.html',
|
||||
styleUrls: ['./projector.component.css']
|
||||
selector: 'app-projector',
|
||||
templateUrl: './projector.component.html',
|
||||
styleUrls: ['./projector.component.css']
|
||||
})
|
||||
export class ProjectorComponent extends BaseComponent implements OnInit {
|
||||
export class ProjectorComponent implements OnInit {
|
||||
|
||||
constructor(protected titleService: Title) {
|
||||
super(titleService)
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.setTitle("Projector");
|
||||
}
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
}
|
||||
|
4
client/src/app/site/alert.component.html
Normal file
4
client/src/app/site/alert.component.html
Normal file
@ -0,0 +1,4 @@
|
||||
<div *ngIf="alert" [ngClass]="cssClass(alert)" class="alert-dismissable">
|
||||
{{alert.message}}
|
||||
<a class="close" (click)="removeAlert(alert)">×</a>
|
||||
</div>
|
34
client/src/app/site/alert.component.ts
Normal file
34
client/src/app/site/alert.component.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
|
||||
import { Alert, AlertType } from './alert';
|
||||
|
||||
@Component({
|
||||
selector: 'alert',
|
||||
templateUrl: './alert.component.html',
|
||||
styleUrls: ['./alert.component.css']
|
||||
})
|
||||
export class AlertComponent implements OnInit {
|
||||
@Input() alert: Alert;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
removeAlert(alert: Alert) {
|
||||
this.alert = undefined;
|
||||
}
|
||||
|
||||
cssClass(alert: Alert) {
|
||||
// return css class based on alert type
|
||||
switch (alert.type) {
|
||||
case AlertType.Success:
|
||||
return 'alert alert-success';
|
||||
case AlertType.Error:
|
||||
return 'alert alert-danger';
|
||||
case AlertType.Info:
|
||||
return 'alert alert-info';
|
||||
case AlertType.Warning:
|
||||
return 'alert alert-warning';
|
||||
}
|
||||
}
|
||||
}
|
33
client/src/app/site/alert.service.ts
Normal file
33
client/src/app/site/alert.service.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Alert, AlertType } from './alert';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AlertService {
|
||||
constructor() { }
|
||||
|
||||
success(message: string): Alert {
|
||||
return this.alert(AlertType.Success, message);
|
||||
}
|
||||
|
||||
error(message: string): Alert {
|
||||
return this.alert(AlertType.Error, message);
|
||||
}
|
||||
|
||||
info(message: string): Alert {
|
||||
return this.alert(AlertType.Info, message);
|
||||
}
|
||||
|
||||
warn(message: string): Alert {
|
||||
return this.alert(AlertType.Warning, message);
|
||||
}
|
||||
|
||||
alert(type: AlertType, message: string): Alert {
|
||||
return <Alert>{ type: type, message: message };
|
||||
}
|
||||
|
||||
// TODO fromHttpError() to generate alerts form http errors
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
<h1> The actual OpenSldies Content! <h2>
|
||||
<router-outlet></router-outlet>
|
||||
<h1>The actual OpenSldies Content!</h1>
|
||||
<nav>A nav will be here</nav>
|
||||
<router-outlet></router-outlet>
|
||||
<footer>Footer</footer>
|
@ -1,15 +1,13 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-site',
|
||||
templateUrl: './site.component.html',
|
||||
styleUrls: ['./site.component.css']
|
||||
selector: 'app-site',
|
||||
templateUrl: './site.component.html',
|
||||
styleUrls: ['./site.component.css']
|
||||
})
|
||||
export class SiteComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
ngOnInit() { }
|
||||
}
|
||||
|
0
client/src/app/site/start.component.css
Normal file
0
client/src/app/site/start.component.css
Normal file
7
client/src/app/site/start.component.html
Normal file
7
client/src/app/site/start.component.html
Normal file
@ -0,0 +1,7 @@
|
||||
<p>
|
||||
start works!
|
||||
Here the welcome text is displayed
|
||||
</p>
|
||||
<button type="button" (click)="logout()" class="btn btn-primary">
|
||||
Logoff test!
|
||||
</button>
|
22
client/src/app/site/start.component.ts
Normal file
22
client/src/app/site/start.component.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { TitleService } from '../core/title.service';
|
||||
import {AuthService } from '../core/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-start',
|
||||
templateUrl: './start.component.html',
|
||||
styleUrls: ['./start.component.css']
|
||||
})
|
||||
export class StartComponent implements OnInit {
|
||||
|
||||
constructor(private titleService: TitleService, private auth: AuthService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('Start page');
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.auth.logout();
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<p>
|
||||
start works!
|
||||
</p>
|
@ -1,20 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BaseComponent } from '../base.component';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-start',
|
||||
templateUrl: './start.component.html',
|
||||
styleUrls: ['./start.component.css']
|
||||
})
|
||||
export class StartComponent extends BaseComponent implements OnInit {
|
||||
|
||||
constructor(titleService: Title) {
|
||||
super(titleService)
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.setTitle("Start page");
|
||||
}
|
||||
|
||||
}
|
@ -4,9 +4,8 @@
|
||||
<img src="/assets/img/openslides-logo.png" alt="OpenSlides" class="login-logo center-block">
|
||||
</div>
|
||||
<div class="modal-body loginForm">
|
||||
{{info}}
|
||||
<!-- Instead of the original approach, user alert component -->
|
||||
<alert></alert>
|
||||
<alert [alert]="alert"></alert>
|
||||
|
||||
<div class="input-group form-group">
|
||||
<div class="input-group-addon">
|
58
client/src/app/users/login.component.ts
Normal file
58
client/src/app/users/login.component.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { User } from '../users/user';
|
||||
import { AuthService } from '../core/auth.service';
|
||||
import { AlertService } from '../site/alert.service';
|
||||
import { TitleService } from '../core/title.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.css']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
user: User = {
|
||||
username: '',
|
||||
password: ''
|
||||
};
|
||||
|
||||
constructor(
|
||||
private titleService: TitleService,
|
||||
private authService: AuthService,
|
||||
private alertService: AlertService,
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
//TODO translate
|
||||
this.titleService.setTitle('Anmelden');
|
||||
}
|
||||
|
||||
//Todo: This serves as a prototype and need enhancement,
|
||||
//like saving a "logged in state" and real checking the server
|
||||
//if logIn was fine
|
||||
onSubmit() {
|
||||
this.authService.loginUser(this.user).subscribe(
|
||||
res => {
|
||||
// TODO an error is thrown here. Also all this stuff should the the auth service..
|
||||
/*if (res.status === 400) {
|
||||
// TODO Use the error that comes from the server
|
||||
//this.alertService.error("Benutzername oder Passwort war nicht korrekt.");
|
||||
} else {
|
||||
if (this.authService.isLoggedIn) {
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
let redirect = this.authService.redirectUrl ?
|
||||
this.authService.redirectUrl : '/';
|
||||
|
||||
// TODO check, if there is a redirect url. Else redirect to /
|
||||
|
||||
// Redirect the user
|
||||
this.router.navigate([redirect]);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user