First Idea for the DataStore
This commit is contained in:
parent
b9116b799d
commit
8b31fa15f2
5
client/src/app/core/exceptions.ts
Normal file
5
client/src/app/core/exceptions.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export class ImproperlyConfiguredError extends Error {
|
||||
constructor(m: string) {
|
||||
super(m);
|
||||
}
|
||||
}
|
48
client/src/app/core/models/baseModel.ts
Normal file
48
client/src/app/core/models/baseModel.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { DS } from 'app/core/services/DS.service';
|
||||
|
||||
const INVALID_COLLECTION_STRING = 'invalid-collection-string';
|
||||
|
||||
export type ModelId = number | string;
|
||||
|
||||
export abstract class BaseModel {
|
||||
abstract id: ModelId;
|
||||
|
||||
constructor() {}
|
||||
|
||||
// Typescript does not allow static and abstract at the same time :(((
|
||||
static getCollectionString(): string {
|
||||
return INVALID_COLLECTION_STRING;
|
||||
}
|
||||
|
||||
private static getCheckedCollectionString(): string {
|
||||
const collectionString: string = this.getCollectionString();
|
||||
if (collectionString === INVALID_COLLECTION_STRING) {
|
||||
throw new ImproperlyConfigured(
|
||||
'Invalid collection string: Please override the static getCollectionString method!'
|
||||
);
|
||||
}
|
||||
return collectionString;
|
||||
}
|
||||
|
||||
protected static _get<T extends BaseModel>(id: ModelId): T | undefined {
|
||||
return DS.get(this.getCheckedCollectionString(), id) as T;
|
||||
}
|
||||
protected static _getAll<T extends BaseModel>(): T[] {
|
||||
return DS.getAll(this.getCheckedCollectionString()) as T[];
|
||||
}
|
||||
protected static _filter<T extends BaseModel>(callback): T[] {
|
||||
return DS.filter(this.getCheckedCollectionString(), callback) as T[];
|
||||
}
|
||||
|
||||
abstract getCollectionString(): string;
|
||||
|
||||
save(): Observable<any> {
|
||||
return DS.save(this);
|
||||
}
|
||||
|
||||
delete(): Observable<any> {
|
||||
return DS.delete(this);
|
||||
}
|
||||
}
|
29
client/src/app/core/models/group.ts
Normal file
29
client/src/app/core/models/group.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { BaseModel } from './baseModel';
|
||||
|
||||
export class Group extends BaseModel {
|
||||
id: number;
|
||||
name: string;
|
||||
permissions: string[];
|
||||
|
||||
constructor(id: number) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static getCollectionString(): string {
|
||||
return 'users/group';
|
||||
}
|
||||
static get(id: number): Group | undefined {
|
||||
return this._get<Group>(id);
|
||||
}
|
||||
static getAll(): Group[] {
|
||||
return this._getAll<Group>();
|
||||
}
|
||||
static filter(callback): Group[] {
|
||||
return this._filter<Group>(callback);
|
||||
}
|
||||
|
||||
getCollectionString(): string {
|
||||
return 'users/group';
|
||||
}
|
||||
}
|
@ -1,4 +1,46 @@
|
||||
export class User {
|
||||
import { BaseModel } from './baseModel';
|
||||
|
||||
export class User extends BaseModel {
|
||||
id: number;
|
||||
username: string;
|
||||
password: string;
|
||||
title: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
structure_level: string;
|
||||
number: string;
|
||||
about_me: string;
|
||||
groups_id: number[];
|
||||
is_present: boolean;
|
||||
is_committee: boolean;
|
||||
email: string;
|
||||
last_email_send?: string;
|
||||
comment: string;
|
||||
is_active: boolean;
|
||||
default_password: string;
|
||||
|
||||
constructor(id: number) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static getCollectionString(): string {
|
||||
return 'users/user';
|
||||
}
|
||||
// Make this static lookup methods typesafe
|
||||
// TODO: I'm not happy about this:
|
||||
// - this has to be done for every model
|
||||
// - this may be extendet, if there are more static functionallities for models.
|
||||
static get(id: number): User | undefined {
|
||||
return this._get<User>(id);
|
||||
}
|
||||
static getAll(): User[] {
|
||||
return this._getAll<User>();
|
||||
}
|
||||
static filter(callback): User[] {
|
||||
return this._filter<User>(callback);
|
||||
}
|
||||
|
||||
getCollectionString(): string {
|
||||
return 'users/user';
|
||||
}
|
||||
}
|
||||
|
16
client/src/app/core/services/DS.service.spec.ts
Normal file
16
client/src/app/core/services/DS.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { DS } from './DS.service';
|
||||
|
||||
describe('DS', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [DS]
|
||||
});
|
||||
});
|
||||
|
||||
/*it('should be created', inject([DSService], (DS: DSService) => {
|
||||
expect(DS).toBeTruthy();
|
||||
}));*/
|
||||
// just a static use
|
||||
});
|
90
client/src/app/core/services/DS.service.ts
Normal file
90
client/src/app/core/services/DS.service.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
import { ImproperlyConfiguredError } from 'app/core/exceptions';
|
||||
import { BaseModel, ModelId } from 'app/core/models/baseModel';
|
||||
|
||||
interface Collection {
|
||||
[id: number]: BaseModel;
|
||||
}
|
||||
|
||||
interface DataStore {
|
||||
[collectionString: string]: Collection;
|
||||
}
|
||||
|
||||
export class DS {
|
||||
static DS: DataStore;
|
||||
|
||||
private constructor() {} // Just a static class!
|
||||
|
||||
static get(collectionString: string, id: ModelId): BaseModel | undefined {
|
||||
const collection: Collection = DS[collectionString];
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
const model: BaseModel = collection[id];
|
||||
return model;
|
||||
}
|
||||
static getAll(collectionString: string): BaseModel[] {
|
||||
const collection: Collection = DS[collectionString];
|
||||
if (!collection) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(collection);
|
||||
}
|
||||
// TODO: type for callback function
|
||||
static filter(collectionString: string, callback): BaseModel[] {
|
||||
return this.getAll(collectionString).filter(callback);
|
||||
}
|
||||
|
||||
static inject(collectionString: string, model: BaseModel): void {
|
||||
if (!model.id) {
|
||||
throw new ImproperlyConfiguredError('The model must have an id!');
|
||||
}
|
||||
if (model.getCollectionString() !== collectionString) {
|
||||
throw new ImproperlyConfiguredError('The model you try to insert has not the right collection string');
|
||||
}
|
||||
if (!DS[collectionString]) {
|
||||
DS[collectionString] = {};
|
||||
}
|
||||
DS[collectionString][model.id] = model;
|
||||
}
|
||||
|
||||
static injectMany(collectionString: string, models: BaseModel[]): void {
|
||||
models.forEach(model => {
|
||||
DS.inject(collectionString, model);
|
||||
});
|
||||
}
|
||||
|
||||
static eject(collectionString: string, id: ModelId) {
|
||||
if (DS[collectionString]) {
|
||||
delete DS[collectionString][id];
|
||||
}
|
||||
}
|
||||
static ejectMany(collectionString: string, ids: ModelId[]) {
|
||||
ids.forEach(id => {
|
||||
DS.eject(collectionString, id);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO remove the any there and in BaseModel.
|
||||
static save(model: BaseModel): Observable<any> {
|
||||
if (!model.id) {
|
||||
throw new ImproperlyConfiguredError('The model must have an id!');
|
||||
}
|
||||
const collectionString: string = model.getCollectionString();
|
||||
// make http request to the server
|
||||
// if this was a success, inject the model into the DS
|
||||
return of();
|
||||
}
|
||||
|
||||
// TODO remove the any there and in BaseModel.
|
||||
static delete(model: BaseModel): Observable<any> {
|
||||
if (!model.id) {
|
||||
throw new ImproperlyConfiguredError('The model must have an id!');
|
||||
}
|
||||
const collectionString: string = model.getCollectionString();
|
||||
// make http request to the server
|
||||
// if this was a success, eject the model from the DS
|
||||
return of();
|
||||
}
|
||||
}
|
@ -43,9 +43,14 @@ export class AuthService {
|
||||
}
|
||||
|
||||
//loggins a users. expects a user model
|
||||
login(user: User): Observable<User | any> {
|
||||
login(username: string, password: string): Observable<User | any> {
|
||||
const user: any = {
|
||||
username: username,
|
||||
password: password
|
||||
};
|
||||
return this.http.post<User>('/users/login/', user, httpOptions).pipe(
|
||||
tap(val => {
|
||||
localStorage.setItem('username', val.username);
|
||||
this.isLoggedIn = true;
|
||||
//Set the session cookie in local storrage.
|
||||
//TODO needs validation
|
||||
|
@ -8,14 +8,14 @@
|
||||
<tr>
|
||||
<td>
|
||||
<mat-form-field class="login-full-widht">
|
||||
<input matInput placeholder="Username" [(ngModel)]="user.username" name="username" required>
|
||||
<input matInput placeholder="Username" [(ngModel)]="username" name="username" required>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<mat-form-field class="example-full-width">
|
||||
<input matInput placeholder="Password" [(ngModel)]="user.password" type="password" name="password" required>
|
||||
<input matInput placeholder="Password" [(ngModel)]="password" type="password" name="password" required>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</tr>
|
||||
@ -26,4 +26,4 @@
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button (click)="formLogin()" color="primary">Login</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</mat-card>
|
||||
|
@ -4,7 +4,6 @@ import { Title } from '@angular/platform-browser';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { User } from 'app/core/models/user';
|
||||
import { AuthService } from 'app/core/services/auth.service';
|
||||
|
||||
@Component({
|
||||
@ -13,10 +12,8 @@ import { AuthService } from 'app/core/services/auth.service';
|
||||
styleUrls: ['./login.component.css']
|
||||
})
|
||||
export class LoginComponent extends BaseComponent implements OnInit {
|
||||
user: User = {
|
||||
username: '',
|
||||
password: ''
|
||||
};
|
||||
username = '';
|
||||
password = '';
|
||||
info: string;
|
||||
|
||||
constructor(
|
||||
@ -48,7 +45,7 @@ export class LoginComponent extends BaseComponent implements OnInit {
|
||||
//like saving a "logged in state" and real checking the server
|
||||
//if logIn was fine
|
||||
formLogin(): void {
|
||||
this.authService.login(this.user).subscribe(res => {
|
||||
this.authService.login(this.username, this.password).subscribe(res => {
|
||||
if (res.status === 400) {
|
||||
//TODO translate
|
||||
console.log('res: ', res);
|
||||
@ -57,8 +54,6 @@ export class LoginComponent extends BaseComponent implements OnInit {
|
||||
// this.toastService.success('Logged in! :)');
|
||||
this.setInfo();
|
||||
if (this.authService.isLoggedIn) {
|
||||
localStorage.setItem('username', res.user.username);
|
||||
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
const redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/';
|
||||
|
@ -6,4 +6,5 @@
|
||||
<span>{{'Welcome to OpenSlides' | translate}}</span>
|
||||
<br/>
|
||||
<p translate [translateParams]="{user: 'Tim'}">Hello user</p>
|
||||
</div>
|
||||
<button type="button" (click)="test()">test</button>
|
||||
</div>
|
||||
|
@ -2,6 +2,10 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
|
||||
// for testing the DS and BaseModel
|
||||
import { User } from 'app/core/models/user';
|
||||
import { DS } from 'app/core/services/DS.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-start',
|
||||
templateUrl: './start.component.html',
|
||||
@ -15,4 +19,22 @@ export class StartComponent extends BaseComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
super.setTitle('Start page');
|
||||
}
|
||||
|
||||
test() {
|
||||
// This can be a basic unit test ;)
|
||||
console.log(User.get(1));
|
||||
const user1: User = new User(1);
|
||||
user1.username = 'testuser';
|
||||
const user2: User = new User(2);
|
||||
user2.username = 'testuser2';
|
||||
|
||||
DS.injectMany(User.getCollectionString(), [user1, user2]);
|
||||
console.log(User.getAll());
|
||||
console.log(User.filter(user => user.id === 1));
|
||||
|
||||
DS.eject(User.getCollectionString(), user1.id);
|
||||
console.log(User.getAll());
|
||||
console.log(User.filter(user => user.id === 1));
|
||||
console.log(User.filter(user => user.id === 2));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user