autoupdate, permissions, operator, directive
-overworked login and logout -new directive 'appOsPerms' (former os-perms) -appOsPerms compares with groups in Operator -login observes operator for user-information (also serves as example on how to user observables and subjects) -operator observes datastore for groups (so the operators knows it's groups by creation or directly after an autoupdate)
This commit is contained in:
parent
2331ecd6b8
commit
30ac9c8e36
41
client/package-lock.json
generated
41
client/package-lock.json
generated
@ -4271,7 +4271,8 @@
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@ -4292,12 +4293,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@ -4312,17 +4315,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@ -4439,7 +4445,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@ -4451,6 +4458,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@ -4465,6 +4473,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@ -4472,12 +4481,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@ -4496,6 +4507,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@ -4576,7 +4588,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@ -4588,6 +4601,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@ -4673,7 +4687,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@ -4709,6 +4724,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@ -4728,6 +4744,7 @@
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@ -4771,12 +4788,14 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,16 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { OpenslidesService } from 'app/core/services/openslides.service';
|
||||
import { AutoupdateService } from 'app/core/services/autoupdate.service';
|
||||
// import { AuthService } from 'app/core/services/auth.service';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
// export class AppComponent implements OnInit {
|
||||
export class AppComponent {
|
||||
constructor(
|
||||
private openSlides: OpenslidesService,
|
||||
private operator: OperatorService,
|
||||
private autoupdate: AutoupdateService,
|
||||
private translate: TranslateService
|
||||
) {
|
||||
@ -23,8 +25,4 @@ export class AppComponent implements OnInit {
|
||||
// try to use the browser language if it is available. If not, uses english.
|
||||
translate.use(translate.getLangs().includes(browserLang) ? browserLang : 'en');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.openSlides.bootup();
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import { AlertComponent } from './core/directives/alert/alert.component';
|
||||
//translation module. TODO: Potetially a SharedModule and own files
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { PruningTranslationLoader } from './core/pruning-loader';
|
||||
import { OsPermsDirective } from './core/directives/os-perms.directive';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient) {
|
||||
return new PruningTranslationLoader(http);
|
||||
@ -60,7 +61,8 @@ library.add(fas);
|
||||
SiteComponent,
|
||||
StartComponent,
|
||||
ProjectorContainerComponent,
|
||||
AlertComponent
|
||||
AlertComponent,
|
||||
OsPermsDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -1,20 +1,16 @@
|
||||
import { Injector } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { DataStoreService } from 'app/core/services/DS.service';
|
||||
// import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
// provides functions that might be used by a lot of components
|
||||
export abstract class BaseComponent {
|
||||
protected injector: Injector;
|
||||
protected dataStore: DataStoreService;
|
||||
// would die in every scope change. disabled for now
|
||||
// protected _translateService: TranslateService;
|
||||
private titleSuffix = ' - OpenSlides 3';
|
||||
|
||||
constructor(protected titleService?: Title) {
|
||||
// throws a warning even tho it is the new syntax. Ignored for now.
|
||||
this.injector = Injector.create([{ provide: DataStoreService, useClass: DataStoreService, deps: [] }]);
|
||||
// this._injector = Injector.create([{ provide: TranslateService, useClass: TranslateService, deps: [] }]);
|
||||
}
|
||||
|
||||
setTitle(prefix: string) {
|
||||
@ -29,11 +25,4 @@ export abstract class BaseComponent {
|
||||
}
|
||||
return this.dataStore;
|
||||
}
|
||||
|
||||
// get translate(): TranslateService {
|
||||
// if (this._translateService == null) {
|
||||
// this._translateService = this._injector.get(TranslateService);
|
||||
// }
|
||||
// return this._translateService;
|
||||
// }
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { OsPermsDirective } from './os-perms.directive';
|
||||
|
||||
describe('OsPermsDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new OsPermsDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
69
client/src/app/core/directives/os-perms.directive.ts
Normal file
69
client/src/app/core/directives/os-perms.directive.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Directive, Input, ElementRef, TemplateRef, ViewContainerRef, OnInit } from '@angular/core';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { Group } from 'app/core/models/users/group';
|
||||
|
||||
@Directive({
|
||||
selector: '[appOsPerms]'
|
||||
})
|
||||
export class OsPermsDirective extends BaseComponent {
|
||||
private userPermissions: string[];
|
||||
private permissions;
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private template: TemplateRef<any>,
|
||||
private viewContainer: ViewContainerRef, //TODO private operator. OperatorService
|
||||
private operator: OperatorService
|
||||
) {
|
||||
super();
|
||||
this.userPermissions = [];
|
||||
|
||||
// observe groups of operator, so the directive can actively react to changes
|
||||
this.operator.getObservable().subscribe(content => {
|
||||
console.log('os-perms did monitor changes in observer: ', content);
|
||||
if (content instanceof Group && this.permissions !== '') {
|
||||
console.log('content was a Group');
|
||||
this.userPermissions = [...this.userPermissions, ...content.permissions];
|
||||
this.updateView();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Input()
|
||||
set appOsPerms(value) {
|
||||
this.permissions = value;
|
||||
this.readUserPermissions();
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
private readUserPermissions(): void {
|
||||
const opGroups = this.operator.getGroups();
|
||||
console.log('operator Groups: ', opGroups);
|
||||
opGroups.forEach(group => {
|
||||
this.userPermissions = [...this.userPermissions, ...group.permissions];
|
||||
});
|
||||
}
|
||||
|
||||
// hides or shows a contrainer
|
||||
private updateView(): void {
|
||||
if (this.checkPermissions()) {
|
||||
// will just render the page normally
|
||||
this.viewContainer.createEmbeddedView(this.template);
|
||||
} else {
|
||||
// will remove the content of the container
|
||||
this.viewContainer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// checks for the required permission
|
||||
private checkPermissions(): boolean {
|
||||
let isPermitted = false;
|
||||
if (this.userPermissions && this.permissions) {
|
||||
this.permissions.forEach(perm => {
|
||||
isPermitted = this.userPermissions.find(userPerm => userPerm === perm) ? true : false;
|
||||
});
|
||||
}
|
||||
return isPermitted;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { Observable, of, BehaviorSubject } from 'rxjs';
|
||||
import { tap, map } from 'rxjs/operators';
|
||||
|
||||
import { ImproperlyConfiguredError } from 'app/core/exceptions';
|
||||
import { BaseModel, ModelId } from 'app/core/models/baseModel';
|
||||
@ -28,6 +28,8 @@ const httpOptions = {
|
||||
export class DataStoreService {
|
||||
// needs to be static cause becauseusing dependency injection, services are unique for a scope.
|
||||
private static store: Storrage = {};
|
||||
// observe datastore to enable dynamic changes in models and view
|
||||
private static dataStoreSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
@ -58,7 +60,7 @@ export class DataStoreService {
|
||||
}
|
||||
|
||||
// TODO: type for callback function
|
||||
// example: this.DS.filder(User, myUser => myUser.first_name === "Max")
|
||||
// example: this.DS.filter(User, myUser => myUser.first_name === "Max")
|
||||
filter(Type, callback): BaseModel[] {
|
||||
let filterCollection = [];
|
||||
const typeCollection = this.get(Type);
|
||||
@ -86,7 +88,7 @@ export class DataStoreService {
|
||||
DataStoreService.store[collectionString] = {};
|
||||
}
|
||||
DataStoreService.store[collectionString][model.id] = model;
|
||||
// console.log('add model ', model, ' into Datastore');
|
||||
this.setObservable(model);
|
||||
});
|
||||
}
|
||||
|
||||
@ -132,4 +134,12 @@ export class DataStoreService {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public getObservable(): Observable<any> {
|
||||
return DataStoreService.dataStoreSubject.asObservable();
|
||||
}
|
||||
|
||||
private setObservable(value) {
|
||||
DataStoreService.dataStoreSubject.next(value);
|
||||
}
|
||||
}
|
||||
|
@ -2,30 +2,23 @@ import { Injectable } from '@angular/core';
|
||||
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
import { OperatorService } from './operator.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
constructor(private authService: AuthService, private operator: OperatorService, private router: Router) {}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
|
||||
const url: string = state.url;
|
||||
return this.checkLogin(url);
|
||||
}
|
||||
|
||||
checkLogin(url: string): boolean {
|
||||
//check if the user is already logged in.
|
||||
//TODO: This is faked
|
||||
if (this.authService.isLoggedIn) {
|
||||
if (this.operator.id) {
|
||||
return true;
|
||||
} else {
|
||||
this.authService.redirectUrl = url;
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the attempted URL for redirecting
|
||||
this.authService.redirectUrl = url;
|
||||
|
||||
// Navigate to the login page with extras
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angul
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
|
||||
import { User } from 'app/core/models/users/user';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
|
||||
const httpOptions = {
|
||||
withCredentials: true,
|
||||
@ -16,54 +16,27 @@ const httpOptions = {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
isLoggedIn: boolean;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the service by querying the server
|
||||
// Not sure if this makes sense, since a service is not supposed to init()
|
||||
init(): Observable<User | any> {
|
||||
return this.http.get<User>('/users/whoami/', httpOptions).pipe(
|
||||
tap(val => {
|
||||
console.log('auth-init-whami : ', val);
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
constructor(private http: HttpClient, private operator: OperatorService) {}
|
||||
|
||||
//loggins a users. expects a user model
|
||||
login(username: string, password: string): Observable<User | any> {
|
||||
login(username: string, password: string): Observable<any> {
|
||||
const user: any = {
|
||||
username: username,
|
||||
password: password
|
||||
};
|
||||
return this.http.post<any>('/users/login/', user, httpOptions).pipe(
|
||||
tap(val => {
|
||||
localStorage.setItem('username', val.username);
|
||||
this.isLoggedIn = true;
|
||||
}),
|
||||
tap(resp => this.operator.storeUser(resp.user)),
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
//logout the user
|
||||
//TODO not yet used
|
||||
logout(): Observable<User | any> {
|
||||
this.isLoggedIn = false;
|
||||
localStorage.removeItem('username');
|
||||
|
||||
return this.http.post<User>('/users/logout/', {}, httpOptions);
|
||||
logout(): Observable<any> {
|
||||
this.operator.clear();
|
||||
return this.http.post<any>('/users/logout/', {}, httpOptions);
|
||||
}
|
||||
|
||||
//very generic error handling function.
|
||||
|
@ -34,13 +34,18 @@ export class AutoupdateService extends BaseComponent {
|
||||
|
||||
constructor(private websocketService: WebsocketService) {
|
||||
super();
|
||||
}
|
||||
|
||||
// initialte autpupdate Service
|
||||
startAutoupdate(): void {
|
||||
console.log('start autoupdate');
|
||||
this.socket = this.websocketService.connect();
|
||||
this.socket.subscribe(response => {
|
||||
this.storeResponse(response);
|
||||
});
|
||||
}
|
||||
|
||||
//create models out of socket answer
|
||||
// create models out of socket answer
|
||||
storeResponse(socketResponse): void {
|
||||
socketResponse.forEach(model => {
|
||||
switch (model.collection) {
|
||||
|
@ -3,22 +3,22 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
//it seems that this service is useless
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OpenslidesService {
|
||||
constructor(private auth: AuthService, private router: Router) {}
|
||||
|
||||
bootup() {
|
||||
// TODO Lock the interface..
|
||||
this.auth.init().subscribe(whoami => {
|
||||
console.log(whoami);
|
||||
if (!whoami.user && !whoami.guest_enabled) {
|
||||
this.router.navigate(['/login']);
|
||||
} else {
|
||||
// It's ok!
|
||||
}
|
||||
});
|
||||
}
|
||||
// now in authService
|
||||
// bootup() {
|
||||
// // TODO Lock the interface..
|
||||
// this.auth.init().subscribe(whoami => {
|
||||
// console.log(whoami);
|
||||
// if (!whoami.user && !whoami.guest_enabled) {
|
||||
// this.router.navigate(['/login']);
|
||||
// } else {
|
||||
// // It's ok!
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
15
client/src/app/core/services/operator.service.spec.ts
Normal file
15
client/src/app/core/services/operator.service.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { OperatorService } from './operator.service';
|
||||
|
||||
describe('OperatorService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [OperatorService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([OperatorService], (service: OperatorService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
198
client/src/app/core/services/operator.service.ts
Normal file
198
client/src/app/core/services/operator.service.ts
Normal file
@ -0,0 +1,198 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of, BehaviorSubject } from 'rxjs';
|
||||
import { HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
|
||||
import { tap, catchError, share } from 'rxjs/operators';
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { Group } from 'app/core/models/users/group';
|
||||
|
||||
// TODO: Dry
|
||||
const httpOptions = {
|
||||
withCredentials: true,
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
};
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OperatorService extends BaseComponent {
|
||||
// default variables
|
||||
about_me: string;
|
||||
comment: string;
|
||||
default_password: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
groups_id: number[];
|
||||
id: number;
|
||||
is_active: boolean;
|
||||
is_committee: boolean;
|
||||
is_present: boolean;
|
||||
last_email_send: string;
|
||||
last_name: string;
|
||||
number: string;
|
||||
structure_level: string;
|
||||
title: string;
|
||||
username: string;
|
||||
logged_in: boolean;
|
||||
// subject
|
||||
private operatorSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
|
||||
// real groups, once they arrived in datastore
|
||||
private groups: Group[] = new Array();
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
super();
|
||||
|
||||
// recreate old operator from localStorage.
|
||||
if (localStorage.getItem('operator')) {
|
||||
const oldOperator = JSON.parse(localStorage.getItem('operator'));
|
||||
if (Object.keys(oldOperator).length > 0) {
|
||||
this.storeUser(oldOperator);
|
||||
}
|
||||
}
|
||||
|
||||
// observe the datastore now to avoid race conditions. Ensures to
|
||||
// find the groups in time
|
||||
this.observeDataStore();
|
||||
}
|
||||
|
||||
// calls 'whoami' to find out the operator
|
||||
public whoAmI(): Observable<any> {
|
||||
return this.http.get<any>('/users/whoami/', httpOptions).pipe(
|
||||
tap(whoami => {
|
||||
if (whoami && whoami.user) {
|
||||
this.storeUser(whoami.user);
|
||||
}
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
public storeUser(user: any): void {
|
||||
// store in file
|
||||
this.about_me = user.about_me;
|
||||
this.comment = user.comment;
|
||||
this.default_password = user.default_password;
|
||||
this.email = user.email;
|
||||
this.first_name = user.first_name;
|
||||
this.groups_id = user.groups_id;
|
||||
this.id = user.id;
|
||||
this.is_active = user.is_active;
|
||||
this.is_committee = user.is_committee;
|
||||
this.is_present = user.is_present;
|
||||
this.last_email_send = user.last_email_send;
|
||||
this.last_name = user.last_name;
|
||||
this.number = user.number;
|
||||
this.structure_level = user.structure_level;
|
||||
this.title = user.title;
|
||||
this.username = user.username;
|
||||
// also store in localstorrage
|
||||
this.updateLocalStorrage();
|
||||
// update mode to inform observers
|
||||
this.updateMode();
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.about_me = null;
|
||||
this.comment = null;
|
||||
this.default_password = null;
|
||||
this.email = null;
|
||||
this.first_name = null;
|
||||
this.groups_id = null;
|
||||
this.id = null;
|
||||
this.is_active = null;
|
||||
this.is_committee = null;
|
||||
this.is_present = null;
|
||||
this.last_email_send = null;
|
||||
this.last_name = null;
|
||||
this.number = null;
|
||||
this.structure_level = null;
|
||||
this.title = null;
|
||||
this.username = null;
|
||||
this.updateMode();
|
||||
localStorage.removeItem('operator');
|
||||
}
|
||||
|
||||
private updateLocalStorrage(): void {
|
||||
localStorage.setItem('operator', JSON.stringify(this.getUpdateObject()));
|
||||
console.log('update local storrage: groups: ', this.groups_id);
|
||||
}
|
||||
|
||||
private updateMode(): void {
|
||||
this.setObservable(this.getUpdateObject());
|
||||
}
|
||||
|
||||
private getUpdateObject(): any {
|
||||
return {
|
||||
about_me: this.about_me,
|
||||
comment: this.comment,
|
||||
default_password: this.default_password,
|
||||
email: this.email,
|
||||
first_name: this.first_name,
|
||||
groups_id: this.groups_id,
|
||||
id: this.id,
|
||||
is_active: this.is_active,
|
||||
is_committee: this.is_committee,
|
||||
is_present: this.is_present,
|
||||
last_email_send: this.last_email_send,
|
||||
last_name: this.last_name,
|
||||
number: this.number,
|
||||
structure_level: this.structure_level,
|
||||
title: this.title,
|
||||
username: this.username,
|
||||
logged_in: this.logged_in
|
||||
};
|
||||
}
|
||||
|
||||
// observe dataStore to set groups once they are there
|
||||
// TODO logic to remove groups / user from certain groups
|
||||
private observeDataStore(): void {
|
||||
console.log('Operator observes DataStore');
|
||||
this.DS.getObservable().subscribe(newModel => {
|
||||
if (newModel instanceof Group) {
|
||||
this.addGroup(newModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// read out the Groups from the DataStore by the operators 'groups_id'
|
||||
// requires that the DataStore has been setup (websocket.service)
|
||||
// requires that the whoAmI did return a valid operator
|
||||
public readGroupsFromStore(): void {
|
||||
this.DS.filter(Group, myGroup => {
|
||||
if (this.groups_id.includes(myGroup.id)) {
|
||||
this.addGroup(myGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getObservable() {
|
||||
return this.operatorSubject.asObservable();
|
||||
}
|
||||
|
||||
private setObservable(value) {
|
||||
this.operatorSubject.next(value);
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
return this.groups;
|
||||
}
|
||||
|
||||
// if the operator has the corresponding ID, set the group
|
||||
private addGroup(newGroup: Group): void {
|
||||
if (this.groups_id.includes(newGroup.id)) {
|
||||
this.groups.push(newGroup);
|
||||
// inform the observers about new groups (appOsPerms)
|
||||
console.log('pushed a group into operator');
|
||||
this.setObservable(newGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Dry
|
||||
private handleError<T>() {
|
||||
return (error: any): Observable<T> => {
|
||||
console.error(error);
|
||||
return of(error);
|
||||
};
|
||||
}
|
||||
}
|
@ -16,4 +16,12 @@
|
||||
|
||||
<div class="app-content">
|
||||
Agenda Works
|
||||
</div>
|
||||
<br/>
|
||||
<div>
|
||||
everyone should see this
|
||||
</div>
|
||||
<br/>
|
||||
<div *appOsPerms="['agenda.can_see']">
|
||||
Only permitted users should see this
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@ import { MatSnackBar } from '@angular/material';
|
||||
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { AuthService } from 'app/core/services/auth.service';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
@ -19,20 +20,22 @@ export class LoginComponent extends BaseComponent implements OnInit {
|
||||
constructor(
|
||||
titleService: Title,
|
||||
private authService: AuthService,
|
||||
private operator: OperatorService,
|
||||
private router: Router,
|
||||
private snackBar: MatSnackBar
|
||||
) {
|
||||
super(titleService);
|
||||
this.setInfo();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//TODO translate
|
||||
super.setTitle('Anmelden');
|
||||
}
|
||||
super.setTitle('Log In');
|
||||
|
||||
setInfo() {
|
||||
this.info = 'Logged in? ' + (this.authService.isLoggedIn ? 'in' : 'out');
|
||||
// if there is stored login information, try to login directly.
|
||||
this.operator.getObservable().subscribe(user => {
|
||||
if (user && user.id) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openSnackBar(message: string) {
|
||||
@ -41,24 +44,17 @@ export class LoginComponent extends BaseComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
//Todo: This serves as a prototype and need enhancement,
|
||||
//like saving a "logged in state" and real checking the server
|
||||
//if logIn was fine
|
||||
// Todo: This serves as a prototype and need enhancement,
|
||||
// if logIn was fine
|
||||
// like saving a "logged in state" and real checking the server
|
||||
formLogin(): void {
|
||||
this.authService.login(this.username, this.password).subscribe(res => {
|
||||
if (res.status === 400) {
|
||||
//TODO translate
|
||||
console.log('res: ', res);
|
||||
this.openSnackBar(res.error.detail);
|
||||
} else {
|
||||
// this.toastService.success('Logged in! :)');
|
||||
this.setInfo();
|
||||
if (this.authService.isLoggedIn) {
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
if (res.user_id) {
|
||||
const redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/';
|
||||
|
||||
// Redirect the user
|
||||
this.router.navigate([redirect]);
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
<!-- User Menu -->
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<!-- TODO use an operator service or get from whoami -->
|
||||
UserName
|
||||
<!-- Get the username from operator -->
|
||||
{{username}}
|
||||
</mat-expansion-panel-header>
|
||||
<mat-action-row>
|
||||
<button (click)='logOutButton()' mat-button>Logout</button>
|
||||
|
@ -3,6 +3,8 @@ import { Router } from '@angular/router';
|
||||
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
|
||||
|
||||
import { AuthService } from 'app/core/services/auth.service';
|
||||
import { AutoupdateService } from 'app/core/services/autoupdate.service';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@ -15,10 +17,13 @@ import { BaseComponent } from 'app/base.component';
|
||||
styleUrls: ['./site.component.css']
|
||||
})
|
||||
export class SiteComponent extends BaseComponent implements OnInit {
|
||||
username = this.operator.username;
|
||||
isMobile = false;
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private autoupdateService: AutoupdateService,
|
||||
private operator: OperatorService,
|
||||
private router: Router,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
private translate: TranslateService
|
||||
@ -39,7 +44,18 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
||||
|
||||
//get a translation via code: use the translation service
|
||||
this.translate.get('Motions').subscribe((res: string) => {
|
||||
console.log(res);
|
||||
console.log('translation of motions in the target language: ' + res);
|
||||
});
|
||||
|
||||
//start autoupdate if the user is logged in:
|
||||
this.operator.whoAmI().subscribe(resp => {
|
||||
if (resp.user) {
|
||||
this.autoupdateService.startAutoupdate();
|
||||
} else {
|
||||
//if whoami is not sucsessfull, forward to login again
|
||||
this.operator.clear();
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
<div class="app-content" translate>
|
||||
<span>{{'Welcome to OpenSlides' | translate}}</span>
|
||||
<br/>
|
||||
<p translate [translateParams]="{user: 'Tim'}">Hello user</p>
|
||||
<!-- <p translate [translateParams]="{user: 'Tim'}">Hello user</p> -->
|
||||
<p>{{'Hello user' | translate:username}}</p>
|
||||
<button type="button" (click)="DataStoreTest()">DataStoreTest</button>
|
||||
<br/>
|
||||
<button type="button" (click)="TranslateTest()">Translate in console</button>
|
||||
|
@ -5,6 +5,7 @@ import { BaseComponent } from 'app/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core'; //showcase
|
||||
|
||||
// for testing the DS and BaseModel
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
import { User } from 'app/core/models/users/user';
|
||||
import { Group } from 'app/core/models/users/group';
|
||||
|
||||
@ -14,12 +15,15 @@ import { Group } from 'app/core/models/users/group';
|
||||
styleUrls: ['./start.component.css']
|
||||
})
|
||||
export class StartComponent extends BaseComponent implements OnInit {
|
||||
constructor(titleService: Title, private translate: TranslateService) {
|
||||
//useage of translation with variables in code and view
|
||||
username = { user: this.operator.username };
|
||||
|
||||
constructor(titleService: Title, private translate: TranslateService, private operator: OperatorService) {
|
||||
super(titleService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.setTitle('Start page');
|
||||
super.setTitle('Start page'); //TODO translate
|
||||
}
|
||||
|
||||
//quick testing of some data store functions
|
||||
|
35
package.json
35
package.json
@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "openslides",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"prepublish": "bower install && gulp",
|
||||
"karma": "karma start tests/karma/karma.conf.js",
|
||||
"karma:watch": "karma start tests/karma/karma.conf.js --single-run=false"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-mocks": "~1.5.11",
|
||||
"bower": "^1.8.0",
|
||||
"gulp": "~4.0.0",
|
||||
"gulp-angular-gettext": "^2.2.0",
|
||||
"gulp-angular-templatecache": "^2.0.0",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-cssnano": "^2.1.2",
|
||||
"gulp-if": "^2.0.2",
|
||||
"gulp-inject-string": "^1.1.0",
|
||||
"gulp-jshint": "^2.0.4",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-sourcemaps": "^2.6.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"jasmine-core": "^2.6.1",
|
||||
"jshint": "^2.9.4",
|
||||
"karma": "^1.5.0",
|
||||
"karma-chrome-launcher": "^2.0.0",
|
||||
"karma-jasmine": "^1.1.0",
|
||||
"karma-phantomjs-launcher": "^1.0.4",
|
||||
"main-bower-files": "^2.13.1",
|
||||
"sprintf-js": "^1.0.3",
|
||||
"through2": "^2.0.3",
|
||||
"yargs": "^7.1.0"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user