Put/Post motions to server
Temporarily over dataStore, will need own service
This commit is contained in:
parent
133ecb4724
commit
de61505b00
@ -29,6 +29,12 @@ interface Storage {
|
||||
* Use this.DS in an OpenSlides Component to Access the store.
|
||||
* Used by a lot of components, classes and services.
|
||||
* Changes can be observed
|
||||
*
|
||||
* FIXME: The injector does not init the HttpClient Service.
|
||||
* Either remove it from DataStore and make an own Service
|
||||
* fix it somehow
|
||||
* or just do-not let the OpenSlidesComponent inject DataStore to it's
|
||||
* children.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -49,7 +55,9 @@ export class DataStoreService {
|
||||
* Empty constructor for dataStore
|
||||
* @param http use HttpClient to send models back to the server
|
||||
*/
|
||||
constructor(private http: HttpClient) {}
|
||||
constructor(private http: HttpClient) {
|
||||
console.log('constructor of dataStore. http: ', this.http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one, multiple or all ID's from dataStore
|
||||
@ -157,21 +165,29 @@ export class DataStoreService {
|
||||
|
||||
/**
|
||||
* Saves the given model on the server
|
||||
* @param model the BaseModel that shall be removed
|
||||
* @param model the BaseModel that shall be saved
|
||||
* @return Observable of BaseModel
|
||||
*/
|
||||
save(model: BaseModel): Observable<BaseModel> {
|
||||
if (!model.id) {
|
||||
throw new ImproperlyConfiguredError('The model must have an 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)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO not tested
|
||||
return this.http.post<BaseModel>(model.collectionString + '/', model).pipe(
|
||||
tap(response => {
|
||||
console.log('the response: ', response);
|
||||
this.add(model);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { tap, catchError, share } from 'rxjs/operators';
|
||||
import { OpenSlidesComponent } from 'app/openslides.component';
|
||||
import { Group } from 'app/shared/models/users/group';
|
||||
import { User } from '../../shared/models/users/user';
|
||||
|
||||
/**
|
||||
* The operator represents the user who is using OpenSlides.
|
||||
@ -38,6 +39,8 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
username: string;
|
||||
logged_in: boolean;
|
||||
|
||||
private _user: User;
|
||||
|
||||
/**
|
||||
* The subject that can be observed by other instances using observing functions.
|
||||
*/
|
||||
@ -65,7 +68,7 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// observe the datastore now to avoid race conditions. Ensures to
|
||||
// observe the DataStore now to avoid race conditions. Ensures to
|
||||
// find the groups in time
|
||||
this.observeDataStore();
|
||||
}
|
||||
@ -77,7 +80,7 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
return this.http.get<any>('/users/whoami/').pipe(
|
||||
tap(whoami => {
|
||||
if (whoami && whoami.user) {
|
||||
this.storeUser(whoami.user);
|
||||
this.storeUser(whoami.user as User);
|
||||
}
|
||||
}),
|
||||
catchError(this.handleError())
|
||||
@ -87,8 +90,11 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
/**
|
||||
* Store the user Information in the operator, the localStorage and update the Observable
|
||||
* @param user usually a http response that represents a user.
|
||||
*
|
||||
* Todo: Could be refractored to use the actual User Object.
|
||||
* Operator is older than user, so this is still a traditional JS way
|
||||
*/
|
||||
public storeUser(user: any): void {
|
||||
public storeUser(user: User): void {
|
||||
// store in file
|
||||
this.about_me = user.about_me;
|
||||
this.comment = user.comment;
|
||||
@ -106,6 +112,7 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
this.structure_level = user.structure_level;
|
||||
this.title = user.title;
|
||||
this.username = user.username;
|
||||
|
||||
// also store in localstorrage
|
||||
this.updateLocalStorage();
|
||||
// update mode to inform observers
|
||||
@ -187,6 +194,10 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
if (newModel instanceof Group) {
|
||||
this.addGroup(newModel);
|
||||
}
|
||||
|
||||
if (newModel instanceof User && this.id === newModel.id) {
|
||||
this._user = newModel;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -243,4 +254,11 @@ export class OperatorService extends OpenSlidesComponent {
|
||||
this.setObservable(newGroup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the user that corresponds to operator.
|
||||
*/
|
||||
get user(): User {
|
||||
return this._user;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Injector } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
import { DataStoreService } from 'app/core/services/dataStore.service';
|
||||
|
@ -42,6 +42,10 @@ export class Motion extends BaseModel {
|
||||
// by the config above
|
||||
workflow: Workflow;
|
||||
|
||||
// for request
|
||||
title: string;
|
||||
text: string;
|
||||
|
||||
constructor(
|
||||
id?: number,
|
||||
identifier?: string,
|
||||
@ -73,7 +77,7 @@ export class Motion extends BaseModel {
|
||||
this.category_id = category_id;
|
||||
this.motion_block_id = motion_block_id;
|
||||
this.origin = origin || '';
|
||||
this.submitters = submitters || [new MotionSubmitter()];
|
||||
this.submitters = submitters || [];
|
||||
this.supporters_id = supporters_id;
|
||||
this.comments = comments;
|
||||
this.state_id = state_id;
|
||||
@ -83,7 +87,7 @@ export class Motion extends BaseModel {
|
||||
this.attachments_id = attachments_id;
|
||||
this.polls = polls;
|
||||
this.agenda_item_id = agenda_item_id;
|
||||
this.log_messages = log_messages || [new MotionLog()];
|
||||
this.log_messages = log_messages || [];
|
||||
|
||||
this.initDataStoreValues();
|
||||
}
|
||||
@ -120,6 +124,13 @@ export class Motion extends BaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
/** add a new motionSubmitter from user-object */
|
||||
addSubmitter(user: User) {
|
||||
const newSubmitter = new MotionSubmitter(null, user.id);
|
||||
this.submitters.push(newSubmitter);
|
||||
console.log('did addSubmitter. this.submitters: ', this.submitters);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the most current title from versions
|
||||
*/
|
||||
@ -176,7 +187,7 @@ export class Motion extends BaseModel {
|
||||
*/
|
||||
get submitterAsUser() {
|
||||
const submitterIds = [];
|
||||
if (this.submitters) {
|
||||
if (this.submitters && this.submitters.length > 0) {
|
||||
this.submitters.forEach(submitter => {
|
||||
submitterIds.push(submitter.user_id);
|
||||
});
|
||||
@ -187,18 +198,6 @@ export class Motion extends BaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name of the first submitter
|
||||
*/
|
||||
get submitterName() {
|
||||
const submitters = this.submitterAsUser;
|
||||
if (submitters) {
|
||||
return submitters[0];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the category of a motion as object
|
||||
*/
|
||||
|
@ -9,14 +9,14 @@
|
||||
<div class='motion-title on-transition-fade'>
|
||||
<span *ngIf="newMotion">New </span>
|
||||
<span translate>Motion</span>
|
||||
<span *ngIf="!editMotion"> {{motion.identifier}}</span>
|
||||
<span *ngIf="motion && !editMotion"> {{motion.identifier}}</span>
|
||||
<span *ngIf="editMotion && !newMotion"> {{metaInfoForm.get('identifier').value}}</span>
|
||||
<span>:</span>
|
||||
<span *ngIf="!editMotion"> {{motion.currentTitle}}</span>
|
||||
<span *ngIf="motion && !editMotion"> {{motion.currentTitle}}</span>
|
||||
<span *ngIf="editMotion"> {{contentForm.get('currentTitle').value}}</span>
|
||||
<br>
|
||||
<div class='motion-submitter'>
|
||||
<span translate>by</span> {{motion.submitterName}}
|
||||
<div *ngIf="motion" class='motion-submitter'>
|
||||
<span translate>by</span> {{motion.submitterAsUser}}
|
||||
</div>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
@ -49,19 +49,19 @@
|
||||
</div>
|
||||
|
||||
<!-- Submitter -->
|
||||
<div *ngIf="motion.submitterName || editMotion">
|
||||
<div *ngIf="motion && motion.submitters || editMotion">
|
||||
<h3 translate>Submitters</h3>
|
||||
{{motion.submitterName}}
|
||||
{{motion.submitterAsUser}}
|
||||
</div>
|
||||
|
||||
<!-- Supporter -->
|
||||
<div *ngIf='motion.supporters_id && motion.supporters_id.length > 0 || editMotion'>
|
||||
<div *ngIf='motion && motion.supporters_id && motion.supporters_id.length > 0 || editMotion'>
|
||||
<h3 translate>Supporters</h3>
|
||||
<!-- print all motion supporters -->
|
||||
</div>
|
||||
|
||||
<!-- State -->
|
||||
<div *ngIf='motion.state_id || editMotion'>
|
||||
<div *ngIf='motion && motion.state_id || editMotion'>
|
||||
<div *ngIf='!editMotion'>
|
||||
<h3 translate>State</h3>
|
||||
{{motion.state.name}}
|
||||
@ -80,7 +80,7 @@
|
||||
|
||||
<!-- Recommendation -->
|
||||
<!-- The suggestion of the work group weather or not a motion should be accepted -->
|
||||
<div *ngIf='motion.recomBy && (motion.recommendation_id || editMotion)'>
|
||||
<div *ngIf='motion && motion.recomBy && (motion.recommendation_id || editMotion)'>
|
||||
<div *ngIf='!editMotion'>
|
||||
<h3>{{motion.recomBy}}</h3>
|
||||
{{motion.recommendation.name}}
|
||||
@ -98,7 +98,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Category -->
|
||||
<div *ngIf="motion.category_id || editMotion">
|
||||
<div *ngIf="motion && motion.category_id || editMotion">
|
||||
<div *ngIf='!editMotion'>
|
||||
<h3 translate> Category</h3>
|
||||
{{motion.category}}
|
||||
@ -113,7 +113,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Origin -->
|
||||
<div *ngIf="motion.origin || editMotion">
|
||||
<div *ngIf="motion && motion.origin || editMotion">
|
||||
<div *ngIf='!editMotion'>
|
||||
<h3 translate> Origin</h3>
|
||||
{{motion.origin}}
|
||||
@ -153,7 +153,7 @@
|
||||
<form [formGroup]='contentForm' class='expansion-panel-custom-body' (ngSubmit)='saveMotion()'>
|
||||
|
||||
<!-- Title -->
|
||||
<div *ngIf="motion.currentTitle || editMotion">
|
||||
<div *ngIf="motion && motion.currentTitle || editMotion">
|
||||
<div *ngIf='!editMotion'>
|
||||
<h2>{{motion.currentTitle}}</h2>
|
||||
</div>
|
||||
@ -165,15 +165,15 @@
|
||||
<!-- Text -->
|
||||
<!-- TODO: this is a config variable. Read it out -->
|
||||
<h3 translate>The assembly may decide:</h3>
|
||||
<div *ngIf='!editMotion'>
|
||||
<div *ngIf='motion && !editMotion'>
|
||||
<div [innerHtml]='motion.currentText'></div>
|
||||
</div>
|
||||
<mat-form-field *ngIf="editMotion" class='wide-text'>
|
||||
<mat-form-field *ngIf="motion && editMotion" class='wide-text'>
|
||||
<textarea matInput placeholder='Motion Text' formControlName='currentText' [value]='motion.currentText'></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Reason -->
|
||||
<div *ngIf="motion.currentReason || editMotion">
|
||||
<div *ngIf="motion && motion.currentReason || editMotion">
|
||||
<div *ngIf='!editMotion'>
|
||||
<h4 translate>Reason</h4>
|
||||
<div [innerHtml]='motion.currentReason'></div>
|
||||
|
@ -1,37 +1,78 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BaseComponent } from '../../../base.component';
|
||||
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';
|
||||
|
||||
/**
|
||||
* Component for the motion detail view
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-motion-detail',
|
||||
templateUrl: './motion-detail.component.html',
|
||||
styleUrls: ['./motion-detail.component.scss']
|
||||
})
|
||||
export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
// export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
export class MotionDetailComponent implements OnInit {
|
||||
/**
|
||||
* MatExpansionPanel for the meta info
|
||||
*/
|
||||
@ViewChild('metaInfoPanel') metaInfoPanel: MatExpansionPanel;
|
||||
|
||||
/**
|
||||
* MatExpansionPanel for the content panel
|
||||
*/
|
||||
@ViewChild('contentPanel') contentPanel: MatExpansionPanel;
|
||||
|
||||
/**
|
||||
* Target motion. Might be new or old
|
||||
*/
|
||||
motion: Motion;
|
||||
|
||||
/**
|
||||
* Motions meta-info
|
||||
*/
|
||||
metaInfoForm: FormGroup;
|
||||
|
||||
/**
|
||||
* Motion content. Can be a new version
|
||||
*/
|
||||
contentForm: FormGroup;
|
||||
|
||||
/**
|
||||
* Determine if the motion is edited
|
||||
*/
|
||||
editMotion = false;
|
||||
|
||||
/**
|
||||
* Determine if the motion is new
|
||||
*/
|
||||
newMotion = false;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
constructor(private route: ActivatedRoute, private formBuilder: FormBuilder) {
|
||||
super();
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private formBuilder: FormBuilder,
|
||||
private operator: OperatorService,
|
||||
private myDataStore: DataStoreService
|
||||
) {
|
||||
// TODO: Add super again
|
||||
// super();
|
||||
this.createForm();
|
||||
|
||||
console.log('route: ', route.snapshot.url[0].path);
|
||||
|
||||
if (route.snapshot.url[0].path === 'new') {
|
||||
this.newMotion = true;
|
||||
this.editMotion = true;
|
||||
@ -42,10 +83,10 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
console.log('params ', params);
|
||||
|
||||
// has the motion of the DataStore was initialized before.
|
||||
this.motion = this.DS.get(Motion, params.id) as Motion;
|
||||
this.motion = this.myDataStore.get(Motion, params.id) as Motion;
|
||||
|
||||
// Observe motion to get the motion in the parameter and also get the changes
|
||||
this.DS.getObservable().subscribe(newModel => {
|
||||
this.myDataStore.getObservable().subscribe(newModel => {
|
||||
if (newModel instanceof Motion) {
|
||||
if (newModel.id === +params.id) {
|
||||
this.motion = newModel as Motion;
|
||||
@ -105,10 +146,15 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value };
|
||||
this.motion.patchValues(newMotionValues);
|
||||
|
||||
console.log('save motion: this: ', this);
|
||||
// TODO: This is DRAFT. Reads out Motion version directly. Potentially insecure.
|
||||
this.motion.title = this.motion.currentTitle;
|
||||
this.motion.text = this.motion.currentText;
|
||||
|
||||
this.DS.save(this.motion).subscribe(answer => {
|
||||
console.log(answer);
|
||||
this.myDataStore.save(this.motion).subscribe(answer => {
|
||||
console.log('answer, ', answer);
|
||||
if (answer && answer.id && this.newMotion) {
|
||||
this.router.navigate(['./motions/' + answer.id]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -116,7 +162,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
* return all Categories.
|
||||
*/
|
||||
getMotionCategories(): Category[] {
|
||||
const categories = this.DS.get(Category);
|
||||
const categories = this.myDataStore.get(Category);
|
||||
return categories as Category[];
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,9 @@ import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { MatTable, MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
|
||||
/**
|
||||
* Component that displays all the motions in a Table using DataSource.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-motion-list',
|
||||
templateUrl: './motion-list.component.html',
|
||||
@ -28,14 +31,26 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
*/
|
||||
dataSource: MatTableDataSource<Motion>;
|
||||
|
||||
/**
|
||||
* The table itself.
|
||||
*/
|
||||
@ViewChild(MatTable) table: MatTable<Motion>;
|
||||
|
||||
/**
|
||||
* Pagination. Might be turned off to all motions at once.
|
||||
*/
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
|
||||
/**
|
||||
* Sort the Table
|
||||
*/
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
/**
|
||||
* Use for minimal width
|
||||
*/
|
||||
columnsToDisplayMinWidth = ['identifier', 'title', 'state'];
|
||||
|
||||
/**
|
||||
* Use for maximal width
|
||||
*/
|
||||
@ -43,13 +58,16 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Constructor implements title and translation Module.
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*
|
||||
* @param titleService Title
|
||||
* @param translate Translation
|
||||
* @param router Router
|
||||
* @param route Current route
|
||||
*/
|
||||
constructor(
|
||||
public router: Router,
|
||||
titleService: Title,
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
super(titleService, translate);
|
||||
@ -78,6 +96,11 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a motion from list. Executed via click.
|
||||
*
|
||||
* @param motion The row the user clicked at
|
||||
*/
|
||||
selectMotion(motion) {
|
||||
this.router.navigate(['./' + motion.id], { relativeTo: this.route });
|
||||
}
|
||||
@ -102,6 +125,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Download all motions As PDF and DocX
|
||||
*
|
||||
* TODO: Currently does nothing
|
||||
*/
|
||||
downloadMotionsButton() {
|
||||
console.log('Download Motions Button');
|
||||
|
@ -111,8 +111,7 @@ export class StartComponent extends BaseComponent implements OnInit {
|
||||
* function to print datastore
|
||||
*/
|
||||
giveDataStore() {
|
||||
// this.DS.printWhole();
|
||||
console.log('only the motions: \n', this.DS.get(Motion) as Motion[]);
|
||||
this.DS.printWhole();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user