Add data-send, option to delete motion

This commit is contained in:
Sean Engelhardt 2018-08-22 16:03:49 +02:00
parent de61505b00
commit 70416df50b
12 changed files with 157 additions and 97 deletions

View File

@ -7,10 +7,11 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthGuard } from './services/auth-guard.service';
import { AuthService } from './services/auth.service';
import { AutoupdateService } from './services/autoupdate.service';
import { DataStoreService } from './services/dataStore.service';
import { DataStoreService } from './services/data-store.service';
import { OperatorService } from './services/operator.service';
import { WebsocketService } from './services/websocket.service';
import { AddHeaderInterceptor } from './http-interceptor';
import { DataSendService } from './services/data-send.service';
/** Global Core Module. Contains all global (singleton) services
*
@ -23,6 +24,7 @@ import { AddHeaderInterceptor } from './http-interceptor';
AuthService,
AutoupdateService,
DataStoreService,
DataSendService,
OperatorService,
WebsocketService,
{

View File

@ -68,7 +68,13 @@ export class AutoupdateService extends OpenSlidesComponent {
storeResponse(socketResponse): void {
socketResponse.forEach(jsonObj => {
const targetClass = this.getClassFromCollectionString(jsonObj.collection);
if (jsonObj.action === 'deleted') {
console.log('storeResponse detect delete');
this.DS.remove(jsonObj.collection, jsonObj.id);
} else {
this.DS.add(new targetClass().deserialize(jsonObj.data));
}
});
}

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { DataSendService } from './data-send.service';
describe('DataSendService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [DataSendService]
});
});
it('should be created', inject([DataSendService], (service: DataSendService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,74 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BaseModel } from '../../shared/models/base.model';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
/**
* Send data back to server
*
* Contrast to dataStore service
*/
@Injectable({
providedIn: 'root'
})
export class DataSendService {
/**
* Construct a DataSendService
*
* @param http The HTTP Client
*/
constructor(private http: HttpClient) {}
/**
* Save motion in the server
*
* @return Observable from
*/
saveModel(model: BaseModel): Observable<BaseModel> {
if (!model.id) {
return this.http.post<BaseModel>('rest/' + model.collectionString + '/', model).pipe(
tap(
response => {
// TODO: Message, Notify, Etc
console.log('New Model added. Response : ', response);
},
error => console.log('error. ', error)
)
);
} else {
return this.http.put<BaseModel>('rest/' + model.collectionString + '/' + model.id, model).pipe(
tap(
response => {
console.log('Update model. Response : ', response);
},
error => console.log('error. ', error)
)
);
}
}
/**
* Deletes the given model on the server
*
* @param model the BaseModel that shall be removed
* @return Observable of BaseModel
*
* TODO Not tested
*/
delete(model: BaseModel): Observable<BaseModel> {
if (model.id) {
return this.http.delete<BaseModel>('rest/' + model.collectionString + '/' + model.id).pipe(
tap(
response => {
// TODO: Message, Notify, Etc
console.log('the response: ', response);
},
error => console.error('error during delete: ', error)
)
);
} else {
console.error('No model ID to delete');
}
}
}

View File

@ -1,6 +1,6 @@
import { TestBed, inject } from '@angular/core/testing';
import { DataStoreService } from './dataStore.service';
import { DataStoreService } from './data-store.service';
describe('DS', () => {
beforeEach(() => {

View File

@ -1,7 +1,5 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { ImproperlyConfiguredError } from 'app/core/exceptions';
import { BaseModel, ModelId } from 'app/shared/models/base.model';
@ -55,9 +53,7 @@ export class DataStoreService {
* Empty constructor for dataStore
* @param http use HttpClient to send models back to the server
*/
constructor(private http: HttpClient) {
console.log('constructor of dataStore. http: ', this.http);
}
constructor() {}
/**
* Read one, multiple or all ID's from dataStore
@ -153,62 +149,25 @@ export class DataStoreService {
* @param ...ids An or multiple IDs or a list of IDs of BaseModels. use spread operator ("...") for arrays
* @example this.DS.remove(User, myUser.id, 3, 4)
*/
remove(Type, ...ids: ModelId[]): void {
remove(collectionType, ...ids: ModelId[]): void {
console.log('remove from DS: collection', collectionType);
console.log('remove from DS: collection', ids);
let collectionString: string;
if (typeof collectionType === 'string') {
collectionString = collectionType;
} else {
const tempObject = new collectionType();
collectionString = tempObject.collectionString;
}
ids.forEach(id => {
const tempObject = new Type();
if (DataStoreService.store[tempObject.collectionString]) {
delete DataStoreService.store[tempObject.collectionString][id];
console.log(`did remove "${id}" from Datastore "${tempObject.collectionString}"`);
if (DataStoreService.store[collectionString]) {
delete DataStoreService.store[collectionString][id];
}
});
}
/**
* Saves the given model on the server
* @param model the BaseModel that shall be saved
* @return Observable of BaseModel
*/
save(model: BaseModel): Observable<BaseModel> {
if (!model.id) {
return this.http.post<BaseModel>('rest/' + model.collectionString + '/', model).pipe(
tap(
response => {
console.log('New Model added. Response : ', response);
},
error => console.log('error. ', error)
)
);
} else {
return this.http.put<BaseModel>('rest/' + model.collectionString + '/' + model.id, model).pipe(
tap(
response => {
console.log('Update model. Response : ', response);
},
error => console.log('error. ', error)
)
);
}
}
/**
* Deletes the given model on the server
* @param model the BaseModel that shall be removed
* @return Observable of BaseModel
*/
delete(model: BaseModel): Observable<BaseModel> {
if (!model.id) {
throw new ImproperlyConfiguredError('The model must have an id!');
}
// TODO not tested
return this.http.post<BaseModel>(model.collectionString + '/', model).pipe(
tap(response => {
console.log('the response: ', response);
this.remove(model, model.id);
})
);
}
/**
* Observe the dataStore for changes.
* @return an observable behaviorSubject

View File

@ -2,7 +2,7 @@ import { Injector } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { DataStoreService } from 'app/core/services/dataStore.service';
import { DataStoreService } from './core/services/data-store.service';
/**
* injects the {@link DataStoreService} to all its children and provides a generic function to catch errors

View File

@ -19,6 +19,18 @@
<span translate>by</span> {{motion.submitterAsUser}}
</div>
</div>
<span class='spacer'></span>
<button class='on-transition-fade' mat-icon-button [matMenuTriggerFor]="motionExtraMenu">
<fa-icon icon='ellipsis-v'></fa-icon>
</button>
<mat-menu #motionExtraMenu="matMenu">
<!-- TODO the functions for the buttons -->
<button mat-menu-item translate>Export As...</button>
<button mat-menu-item translate>Project</button>
<mat-divider></mat-divider>
<button mat-menu-item class='deleteMotionButton' (click)='deleteMotionButton()' translate>DeleteMotion</button>
</mat-menu>
</mat-toolbar>
<mat-accordion multi='true' class='on-transition-fade'>
@ -85,7 +97,7 @@
<h3>{{motion.recomBy}}</h3>
{{motion.recommendation.name}}
</div>
<mat-form-field *ngIf="editMotion">
<mat-form-field *ngIf="motion && editMotion">
<mat-select placeholder='Recommendation' formControlName='recommendation_id'>
<mat-option *ngFor="let state of motion.possible_states" [value]="state.id">{{state}}</mat-option>
<mat-divider></mat-divider>
@ -103,7 +115,7 @@
<h3 translate> Category</h3>
{{motion.category}}
</div>
<mat-form-field *ngIf="editMotion">
<mat-form-field *ngIf="motion && editMotion">
<mat-select placeholder='Category' formControlName='category_id'>
<mat-option>None</mat-option>
<mat-divider></mat-divider>

View File

@ -6,6 +6,10 @@ span {
background-color: rgb(77, 243, 86);
}
.deleteMotionButton {
color: red;
}
.motion-title {
padding-left: 20px;
line-height: 100%;

View File

@ -5,8 +5,7 @@ import { Motion } from '../../../shared/models/motions/motion';
import { Category } from '../../../shared/models/motions/category';
import { FormGroup, FormBuilder } from '@angular/forms';
import { MatExpansionPanel } from '@angular/material';
import { DataStoreService } from '../../../core/services/dataStore.service';
import { OperatorService } from '../../../core/services/operator.service';
import { DataSendService } from '../../../core/services/data-send.service';
/**
* Component for the motion detail view
@ -16,8 +15,7 @@ import { OperatorService } from '../../../core/services/operator.service';
templateUrl: './motion-detail.component.html',
styleUrls: ['./motion-detail.component.scss']
})
// export class MotionDetailComponent extends BaseComponent implements OnInit {
export class MotionDetailComponent implements OnInit {
export class MotionDetailComponent extends BaseComponent implements OnInit {
/**
* MatExpansionPanel for the meta info
*/
@ -56,8 +54,6 @@ export class MotionDetailComponent implements OnInit {
/**
* Constuct the detail view.
*
* TODO: DataStore needs removed and added via the parent.
* Own service for put and post required
*
* @param route determine if this is a new or an existing motion
* @param formBuilder For reactive forms. Form Group and Form Control
@ -66,11 +62,9 @@ export class MotionDetailComponent implements OnInit {
private router: Router,
private route: ActivatedRoute,
private formBuilder: FormBuilder,
private operator: OperatorService,
private myDataStore: DataStoreService
private dataSend: DataSendService
) {
// TODO: Add super again
// super();
super();
this.createForm();
if (route.snapshot.url[0].path === 'new') {
@ -80,13 +74,11 @@ export class MotionDetailComponent implements OnInit {
} else {
// load existing motion
this.route.params.subscribe(params => {
console.log('params ', params);
// has the motion of the DataStore was initialized before.
this.motion = this.myDataStore.get(Motion, params.id) as Motion;
this.motion = this.DS.get(Motion, params.id) as Motion;
// Observe motion to get the motion in the parameter and also get the changes
this.myDataStore.getObservable().subscribe(newModel => {
this.DS.getObservable().subscribe(newModel => {
if (newModel instanceof Motion) {
if (newModel.id === +params.id) {
this.motion = newModel as Motion;
@ -150,8 +142,7 @@ export class MotionDetailComponent implements OnInit {
this.motion.title = this.motion.currentTitle;
this.motion.text = this.motion.currentText;
this.myDataStore.save(this.motion).subscribe(answer => {
console.log('answer, ', answer);
this.dataSend.saveModel(this.motion).subscribe(answer => {
if (answer && answer.id && this.newMotion) {
this.router.navigate(['./motions/' + answer.id]);
}
@ -162,7 +153,7 @@ export class MotionDetailComponent implements OnInit {
* return all Categories.
*/
getMotionCategories(): Category[] {
const categories = this.myDataStore.get(Category);
const categories = this.DS.get(Category);
return categories as Category[];
}
@ -171,7 +162,6 @@ export class MotionDetailComponent implements OnInit {
*/
editMotionButton() {
this.editMotion ? (this.editMotion = false) : (this.editMotion = true);
if (this.editMotion) {
this.patchForm();
this.metaInfoPanel.open();
@ -181,17 +171,17 @@ export class MotionDetailComponent implements OnInit {
}
}
/**
* Trigger to delete the motion
*/
deleteMotionButton() {
this.dataSend.delete(this.motion).subscribe(answer => {
this.router.navigate(['./motions/']);
});
}
/**
* Init. Does nothing here.
*/
ngOnInit() {}
/**
* Function to download a motion.
*
* TODO: does nothing yet.
*/
downloadSingleMotionButton() {
console.log('Download this motion');
}
}

View File

@ -88,11 +88,9 @@ export class MotionListComponent extends BaseComponent implements OnInit {
// The alternative approach is to put the observable as DataSource to the table
this.DS.getObservable().subscribe(newModel => {
if (newModel instanceof Motion) {
if (!this.motionArray.includes(newModel)) {
this.motionArray.push(newModel as Motion);
this.motionArray = this.DS.get(Motion) as Motion[];
this.dataSource.data = this.motionArray;
}
}
});
}

View File

@ -65,12 +65,12 @@ export class SiteComponent extends BaseComponent implements OnInit {
}
});
//get a translation via code: use the translation service
// get a translation via code: use the translation service
// this.translate.get('Motions').subscribe((res: string) => {
// console.log('translation of motions in the target language: ' + res);
// });
//start autoupdate if the user is logged in:
// start autoupdate if the user is logged in:
this.operator.whoAmI().subscribe(resp => {
if (resp.user) {
this.autoupdateService.startAutoupdate();