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,8 +3,16 @@
|
|||||||
"target": "http://localhost:8000",
|
"target": "http://localhost:8000",
|
||||||
"secure": false
|
"secure": false
|
||||||
},
|
},
|
||||||
|
"/users/logout": {
|
||||||
|
"target": "http://localhost:8000",
|
||||||
|
"secure": false
|
||||||
|
},
|
||||||
|
"/users/whoami": {
|
||||||
|
"target": "http://localhost:8000",
|
||||||
|
"secure": false
|
||||||
|
},
|
||||||
"/rest": {
|
"/rest": {
|
||||||
"target": "http://localhost:8000",
|
"target": "http://localhost:8000",
|
||||||
"secure": false
|
"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 { Component, OnInit } from '@angular/core';
|
||||||
import { BaseComponent } from '../base.component';
|
import { TitleService } from '../core/title.service';
|
||||||
import { Title } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-agenda',
|
selector: 'app-agenda',
|
||||||
templateUrl: './agenda.component.html',
|
templateUrl: './agenda.component.html',
|
||||||
styleUrls: ['./agenda.component.css']
|
styleUrls: ['./agenda.component.css']
|
||||||
})
|
})
|
||||||
export class AgendaComponent extends BaseComponent implements OnInit {
|
export class AgendaComponent implements OnInit {
|
||||||
|
|
||||||
constructor(titleService: Title) {
|
constructor(private titleService: TitleService) {
|
||||||
super(titleService)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
//TODO translate
|
this.titleService.setTitle("Agenda");
|
||||||
super.setTitle("Agenda");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,37 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { LoginComponent } from './login/login.component';
|
|
||||||
import { ProjectorComponent } from "./projector/projector.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 { AgendaComponent } from "./agenda/agenda.component";
|
||||||
import { MotionsComponent } from "./motions/motions.component";
|
import { MotionsComponent } from "./motions/motions.component";
|
||||||
import { SiteComponent } from "./site/site.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 = [
|
const routes: Routes = [
|
||||||
{ path: 'projector', component: ProjectorComponent },
|
{ path: 'projector/:id', component: ProjectorComponent },
|
||||||
{ path: 'login', component: LoginComponent },
|
//{ path: 'projector', redirect: 'projector/1' }, // Test this
|
||||||
{
|
{ path: 'real-projector/:id', component: ProjectorContainerComponent },
|
||||||
path: '',
|
//{ path: 'real-projector', redirect: 'real-projector/1' }, // this too
|
||||||
component: SiteComponent,
|
{
|
||||||
canActivate: [AuthGuard],
|
path: '',
|
||||||
children: [
|
component: SiteComponent,
|
||||||
{ path: '', component: StartComponent },
|
canActivate: [RouterAuthGuard],
|
||||||
{ path: 'agenda', component: AgendaComponent },
|
children: [
|
||||||
{ path: 'motions', component: MotionsComponent },
|
{ path: '', component: StartComponent },
|
||||||
]
|
{ path: 'login', component: LoginComponent },
|
||||||
},
|
{ path: 'agenda', component: AgendaComponent },
|
||||||
{ path: '**', redirectTo: '' },
|
{ path: 'motions', component: MotionsComponent },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ path: '**', redirectTo: '' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule { }
|
export class AppRoutingModule { }
|
||||||
|
@ -1,2 +1 @@
|
|||||||
<router-outlet></router-outlet>
|
<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({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.css']
|
styleUrls: ['./app.component.css']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
title = 'OpenSlides 3';
|
constructor(private openSlides: OpenSlidesService) { }
|
||||||
constructor() { }
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.openSlides.bootup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,17 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
|||||||
import { fas } from '@fortawesome/free-solid-svg-icons';
|
import { fas } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { LoginComponent } from './login/login.component';
|
import { LoginComponent } from './users/login.component';
|
||||||
import { UsersComponent } from './users/users.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 { ProjectorComponent } from './projector/projector.component';
|
||||||
|
import { ProjectorContainerComponent } from './projector/projector-container.component';
|
||||||
import { MotionsComponent } from './motions/motions.component';
|
import { MotionsComponent } from './motions/motions.component';
|
||||||
import { AgendaComponent } from './agenda/agenda.component';
|
import { AgendaComponent } from './agenda/agenda.component';
|
||||||
import { SiteComponent } from './site/site.component';
|
import { SiteComponent } from './site/site.component';
|
||||||
import { StartComponent } from './start/start.component';
|
import { StartComponent } from './site/start.component';
|
||||||
import { AlertComponent } from './_directives/alert/alert.component';
|
import { AlertComponent } from './site/alert.component';
|
||||||
import { AlertService } from './_services/alert.service';
|
import { AlertService } from './site/alert.service';
|
||||||
|
|
||||||
//add font-awesome icons to library.
|
//add font-awesome icons to library.
|
||||||
//will blow up the code.
|
//will blow up the code.
|
||||||
@ -28,6 +29,7 @@ library.add(fas);
|
|||||||
LoginComponent,
|
LoginComponent,
|
||||||
UsersComponent,
|
UsersComponent,
|
||||||
ProjectorComponent,
|
ProjectorComponent,
|
||||||
|
ProjectorContainerComponent,
|
||||||
MotionsComponent,
|
MotionsComponent,
|
||||||
AgendaComponent,
|
AgendaComponent,
|
||||||
SiteComponent,
|
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 { Component, OnInit } from '@angular/core';
|
||||||
import { BaseComponent } from '../base.component';
|
import { TitleService } from '../core/title.service';
|
||||||
import { Title } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-motions',
|
selector: 'app-motions',
|
||||||
templateUrl: './motions.component.html',
|
templateUrl: './motions.component.html',
|
||||||
styleUrls: ['./motions.component.css']
|
styleUrls: ['./motions.component.css']
|
||||||
})
|
})
|
||||||
export class MotionsComponent extends BaseComponent implements OnInit {
|
export class MotionsComponent implements OnInit {
|
||||||
|
|
||||||
constructor(titleService: Title) {
|
constructor(private titleService: TitleService) {
|
||||||
super(titleService)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
super.setTitle("Motions");
|
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';
|
import { ProjectorComponent } from './projector.component';
|
||||||
|
|
||||||
describe('ProjectorComponent', () => {
|
describe('ProjectorComponent', () => {
|
||||||
let component: ProjectorComponent;
|
let component: ProjectorComponent;
|
||||||
let fixture: ComponentFixture<ProjectorComponent>;
|
let fixture: ComponentFixture<ProjectorComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ ProjectorComponent ]
|
declarations: [ ProjectorComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ProjectorComponent);
|
fixture = TestBed.createComponent(ProjectorComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { BaseComponent } from '../base.component';
|
|
||||||
import { Title } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-projector',
|
selector: 'app-projector',
|
||||||
templateUrl: './projector.component.html',
|
templateUrl: './projector.component.html',
|
||||||
styleUrls: ['./projector.component.css']
|
styleUrls: ['./projector.component.css']
|
||||||
})
|
})
|
||||||
export class ProjectorComponent extends BaseComponent implements OnInit {
|
export class ProjectorComponent implements OnInit {
|
||||||
|
|
||||||
constructor(protected titleService: Title) {
|
constructor() {
|
||||||
super(titleService)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
super.setTitle("Projector");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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>
|
<h1>The actual OpenSldies Content!</h1>
|
||||||
<router-outlet></router-outlet>
|
<nav>A nav will be here</nav>
|
||||||
<footer>Footer</footer>
|
<router-outlet></router-outlet>
|
||||||
|
<footer>Footer</footer>
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-site',
|
selector: 'app-site',
|
||||||
templateUrl: './site.component.html',
|
templateUrl: './site.component.html',
|
||||||
styleUrls: ['./site.component.css']
|
styleUrls: ['./site.component.css']
|
||||||
})
|
})
|
||||||
export class SiteComponent implements OnInit {
|
export class SiteComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
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">
|
<img src="/assets/img/openslides-logo.png" alt="OpenSlides" class="login-logo center-block">
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body loginForm">
|
<div class="modal-body loginForm">
|
||||||
{{info}}
|
|
||||||
<!-- Instead of the original approach, user alert component -->
|
<!-- Instead of the original approach, user alert component -->
|
||||||
<alert></alert>
|
<alert [alert]="alert"></alert>
|
||||||
|
|
||||||
<div class="input-group form-group">
|
<div class="input-group form-group">
|
||||||
<div class="input-group-addon">
|
<div class="input-group-addon">
|
||||||
@ -31,4 +30,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
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