Merge pull request #3950 from FinnStutzenstein/refineHttpService

Refine the HTTP Service.
This commit is contained in:
Sean 2018-11-01 11:30:20 +01:00 committed by GitHub
commit 4f7d860280
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 329 additions and 400 deletions

View File

@ -1,6 +1,7 @@
import { TranslateLoader } from '@ngx-translate/core'; import { TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators/'; import { map } from 'rxjs/operators/';
import { Observable } from 'rxjs';
/** /**
* Translation loader that replaces empty strings with nothing. * Translation loader that replaces empty strings with nothing.
@ -28,7 +29,7 @@ export class PruningTranslationLoader implements TranslateLoader {
* Loads a language file, stores the content, give it to the process function. * Loads a language file, stores the content, give it to the process function.
* @param lang language string (en, fr, de, ...) * @param lang language string (en, fr, de, ...)
*/ */
public getTranslation(lang: string): any { public getTranslation(lang: string): Observable<any> {
return this.http.get(`${this.prefix}${lang}${this.suffix}`).pipe(map((res: Object) => this.process(res))); return this.http.get(`${this.prefix}${lang}${this.suffix}`).pipe(map((res: Object) => this.process(res)));
} }

View File

@ -1,11 +1,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BaseModel } from '../../shared/models/base/base-model'; import { BaseModel } from '../../shared/models/base/base-model';
import { Observable } from 'rxjs';
import { HttpService } from './http.service'; import { HttpService } from './http.service';
import { HTTPMethod } from './http.service'; import { Identifiable } from '../../shared/models/base/identifiable';
/** /**
* Send data back to server * Send data back to server. Cares about the right REST routes.
* *
* Contrast to dataStore service * Contrast to dataStore service
*/ */
@ -16,38 +15,47 @@ export class DataSendService {
/** /**
* Construct a DataSendService * Construct a DataSendService
* *
* @param httpService The HTTP Client * @param httpService The HTTP Service
*/ */
public constructor(private httpService: HttpService) {} public constructor(private httpService: HttpService) {}
/** /**
* Sends a post request with the model to the server. * Sends a post request with the model to the server to create it.
* Usually for new Models *
* @param model The model to create.
*/ */
public createModel(model: BaseModel): Observable<BaseModel> { public async createModel(model: BaseModel): Promise<Identifiable> {
const restPath = `rest/${model.collectionString}/`; const restPath = `rest/${model.collectionString}/`;
return this.httpService.create(restPath, model) as Observable<BaseModel>; return await this.httpService.post<Identifiable>(restPath, model);
} }
/** /**
* Function to change a model on the server. * Function to fully update a model on the server.
* *
* @param model the base model that is meant to be changed * @param model The model that is meant to be changed.
* @param method the required http method. might be put or patch
*/ */
public updateModel(model: BaseModel, method: HTTPMethod): Observable<BaseModel> { public async updateModel(model: BaseModel): Promise<void> {
const restPath = `rest/${model.collectionString}/${model.id}`; const restPath = `rest/${model.collectionString}/${model.id}/`;
return this.httpService.update(restPath, model, method) as Observable<BaseModel>; await this.httpService.put(restPath, model);
} }
/** /**
* Deletes the given model on the server * Updates a model partially on the server.
* *
* @param model the BaseModel that shall be removed * @param model The model to partially update.
* @return Observable of BaseModel
*/ */
public deleteModel(model: BaseModel): Observable<BaseModel> { public async partialUpdateModel(model: BaseModel): Promise<void> {
const restPath = `rest/${model.collectionString}/${model.id}`; const restPath = `rest/${model.collectionString}/${model.id}/`;
return this.httpService.delete(restPath) as Observable<BaseModel>; await this.httpService.patch(restPath, model);
}
/**
* Deletes the given model on the server.
*
* @param model the model that shall be deleted.
*/
public async deleteModel(model: BaseModel): Promise<void> {
const restPath = `rest/${model.collectionString}/${model.id}/`;
await this.httpService.delete(restPath);
} }
} }

View File

@ -1,105 +1,92 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
/** /**
* Enum for different HTTPMethods * Enum for different HTTPMethods
*/ */
export enum HTTPMethod { export enum HTTPMethod {
PUT, GET = 'get',
PATCH POST = 'post',
PUT = 'put',
PATCH = 'patch',
DELETE = 'delete'
} }
/**
* Service for managing HTTP requests. Allows to send data for every method. Also (TODO) will do generic error handling.
*/
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
/**
* Service for sending data back to server
*/
export class HttpService { export class HttpService {
/** /**
* Construct a DataSendService * Construct a HttpService
* *
* @param http The HTTP Client * @param http The HTTP Client
*/ */
public constructor(private http: HttpClient) {} public constructor(private http: HttpClient) {}
private async send<T>(url: string, method: HTTPMethod, data?: any): Promise<T> {
if (!url.endsWith('/')) {
url += '/';
}
const options = {
body: data,
};
try {
const response = await this.http.request<T>(method, url, options).toPromise();
return response;
} catch (e) {
console.log("error", e);
throw e;
}
}
/**
* Exectures a get on a url with a certain object
* @param url The url to send the request to.
* @param data An optional payload for the request.
*/
public async get<T>(url: string, data?: any): Promise<T> {
return await this.send<T>(url, HTTPMethod.GET, data);
}
/** /**
* Exectures a post on a url with a certain object * Exectures a post on a url with a certain object
* @param url string of the url to send semothing to * @param url string of the url to send semothing to
* @param obj the object that should be send * @param data The data to send
*/ */
public create(url: string, obj: object): Observable<object> { public async post<T>(url: string, data: any): Promise<T> {
url = this.formatForSlash(url); return await this.send<T>(url, HTTPMethod.POST, data);
return this.http.post<object>(url, obj).pipe(
tap(
response => {
// TODO: Message, Notify, Etc
console.log('New object added. Response :\n ', response);
},
error => console.error('Error:\n ', error)
)
);
} }
/** /**
* Adds a / at the end, if there is none * Exectures a put on a url with a certain object
* @param str the string where the / should be checked
*/
private formatForSlash(str: string): string {
let retStr = '';
retStr += str;
return retStr.endsWith('/') ? retStr : (retStr += '/');
}
/**
* Save object in the server
*
* @param url string of the url to send semothing to * @param url string of the url to send semothing to
* @param obj the object that should be send * @param data the object that should be send
* @param method the HTTP Method that should be used {@link HTTPMethod}
* @return Observable from object
*/ */
public update(url: string, obj: object, method?: HTTPMethod): Observable<object> { public async patch<T>(url: string, data: any): Promise<T> {
url = this.formatForSlash(url); return await this.send<T>(url, HTTPMethod.PATCH, data);
if (method === null || method === HTTPMethod.PATCH) {
return this.http.patch<object>(url, obj).pipe(
tap(
response => {
console.log('Update object. Response :\n ', response);
},
error => console.log('Error:\n ', error)
)
);
} else if (method === HTTPMethod.PUT) {
return this.http.put<object>(url, obj).pipe(
tap(
response => {
console.log('Update object. Response :\n ', response);
},
error => console.error('Error :\n', error)
)
);
}
} }
/** /**
* Deletes the given object on the server * Exectures a put on a url with a certain object
* * @param url the url that should be called
* @param url the url that should be called to delete the object * @param data: The data to send
* @return Observable of object
*/ */
public delete(url: string): Observable<object> { public async put<T>(url: string, data: any): Promise<T> {
url = this.formatForSlash(url); return await this.send<T>(url, HTTPMethod.PUT, data);
return this.http.delete<object>(url).pipe( }
tap(
response => { /**
// TODO: Message, Notify, Etc * Makes a delete request.
console.log('Delete object. Response:\n', response); * @param url the url that should be called
}, * @param data An optional data to send in the requestbody.
error => console.error('Error: \n', error) */
) public async delete<T>(url: string, data?: any): Promise<T> {
); return await this.send<T>(url, HTTPMethod.DELETE, data);
} }
} }

View File

@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { LoginDataService } from '../../../core/services/login-data.service'; import { LoginDataService } from '../../../core/services/login-data.service';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { HttpClient } from '@angular/common/http'; import { HttpService } from '../../../core/services/http.service';
/** /**
* Characterize a plugin. This data is retrieved from the server * Characterize a plugin. This data is retrieved from the server
@ -83,7 +83,7 @@ export class LegalNoticeContentComponent implements OnInit {
public constructor( public constructor(
private loginDataService: LoginDataService, private loginDataService: LoginDataService,
private translate: TranslateService, private translate: TranslateService,
private http: HttpClient private http: HttpService
) {} ) {}
/** /**
@ -97,10 +97,13 @@ export class LegalNoticeContentComponent implements OnInit {
}); });
// Query the version info. // Query the version info.
this.http this.http.get<VersionResponse>(environment.urlPrefix + '/core/version/', {}).then(
.get<VersionResponse>(environment.urlPrefix + '/core/version/', {}) info => {
.subscribe((info: VersionResponse) => {
this.versionInfo = info; this.versionInfo = info;
}); },
() => {
// TODO: error handling if the version info could not be loaded
}
);
} }
} }

View File

@ -1,5 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
@ -7,6 +6,7 @@ import { Item } from '../../../shared/models/agenda/item';
import { ViewItem } from '../models/view-item'; import { ViewItem } from '../models/view-item';
import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model'; import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model';
import { BaseModel } from '../../../shared/models/base/base-model'; import { BaseModel } from '../../../shared/models/base/base-model';
import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository service for users * Repository service for users
@ -49,7 +49,7 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public update(item: Partial<Item>, viewUser: ViewItem): Observable<Item> { public async update(item: Partial<Item>, viewUser: ViewItem): Promise<void> {
return null; return null;
} }
@ -58,7 +58,7 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public delete(item: ViewItem): Observable<Item> { public async delete(item: ViewItem): Promise<void> {
return null; return null;
} }
@ -67,7 +67,7 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public create(item: Item): Observable<Item> { public async create(item: Item): Promise<Identifiable> {
return null; return null;
} }

View File

@ -4,9 +4,9 @@ import { Assignment } from '../../../shared/models/assignments/assignment';
import { User } from '../../../shared/models/users/user'; import { User } from '../../../shared/models/users/user';
import { Tag } from '../../../shared/models/core/tag'; import { Tag } from '../../../shared/models/core/tag';
import { Item } from '../../../shared/models/agenda/item'; import { Item } from '../../../shared/models/agenda/item';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Service for Assignments. * Repository Service for Assignments.
@ -25,15 +25,15 @@ export class AssignmentRepositoryService extends BaseRepository<ViewAssignment,
super(DS, Assignment, [User, Item, Tag]); super(DS, Assignment, [User, Item, Tag]);
} }
public update(assignment: Partial<Assignment>, viewAssignment: ViewAssignment): Observable<Assignment> { public async update(assignment: Partial<Assignment>, viewAssignment: ViewAssignment): Promise<void> {
return null; return null;
} }
public delete(viewAssignment: ViewAssignment): Observable<Assignment> { public async delete(viewAssignment: ViewAssignment): Promise<void> {
return null; return null;
} }
public create(assignment: Assignment): Observable<Assignment> { public async create(assignment: Assignment): Promise<Identifiable> {
return null; return null;
} }

View File

@ -4,6 +4,7 @@ import { BaseViewModel } from './base-view-model';
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service'; import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service';
import { DataStoreService } from '../../core/services/data-store.service'; import { DataStoreService } from '../../core/services/data-store.service';
import { Identifiable } from '../../shared/models/base/identifiable';
export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent { export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent {
/** /**
@ -78,14 +79,14 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
* @param update the update that should be created * @param update the update that should be created
* @param viewModel the view model that the update is based on * @param viewModel the view model that the update is based on
*/ */
public abstract update(update: Partial<M>, viewModel: V): Observable<M>; public abstract async update(update: Partial<M>, viewModel: V): Promise<void>;
/** /**
* Deletes a given Model * Deletes a given Model
* @param update the update that should be created * @param update the update that should be created
* @param viewModel the view model that the update is based on * @param viewModel the view model that the update is based on
*/ */
public abstract delete(viewModel: V): Observable<M>; public abstract async delete(viewModel: V): Promise<void>;
/** /**
* Creates a new model * Creates a new model
@ -93,7 +94,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
* @param viewModel the view model that the update is based on * @param viewModel the view model that the update is based on
* TODO: remove the viewModel * TODO: remove the viewModel
*/ */
public abstract create(update: M): Observable<M>; public abstract async create(update: M): Promise<Identifiable>;
/** /**
* Creates a view model out of a base model. * Creates a view model out of a base model.

View File

@ -5,7 +5,6 @@ import { ViewConfig } from '../../models/view-config';
import { BaseComponent } from '../../../../base.component'; import { BaseComponent } from '../../../../base.component';
import { FormGroup, FormBuilder } from '@angular/forms'; import { FormGroup, FormBuilder } from '@angular/forms';
import { ConfigRepositoryService } from '../../services/config-repository.service'; import { ConfigRepositoryService } from '../../services/config-repository.service';
import { tap } from 'rxjs/operators';
import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher'; import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher';
/** /**
@ -117,26 +116,19 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
/** /**
* Updates the this config field. * Updates the this config field.
*/ */
private update(value: any): void { private async update(value: any): Promise<void> {
// TODO: Fix the Datetimepicker parser and formatter. // TODO: Fix the Datetimepicker parser and formatter.
if (this.configItem.inputType === 'datetimepicker') { if (this.configItem.inputType === 'datetimepicker') {
value = Date.parse(value); value = Date.parse(value);
} }
this.debounceTimeout = null; this.debounceTimeout = null;
this.repo try {
.update({ value: value }, this.configItem) await this.repo.update({ value: value }, this.configItem);
.pipe(
tap(
response => {
this.error = null; this.error = null;
this.showSuccessIcon(); this.showSuccessIcon();
}, } catch (e) {
error => { this.setError(e.error.detail);
this.setError(error.error.detail);
} }
)
)
.subscribe();
} }
/** /**

View File

@ -6,7 +6,8 @@ import { Config } from '../../../shared/models/core/config';
import { Observable, BehaviorSubject } from 'rxjs'; import { Observable, BehaviorSubject } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { ConstantsService } from '../../../core/services/constants.service'; import { ConstantsService } from '../../../core/services/constants.service';
import { HttpClient } from '@angular/common/http'; import { HttpService } from '../../../core/services/http.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Holds a single config item. * Holds a single config item.
@ -85,7 +86,7 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
/** /**
* Constructor for ConfigRepositoryService. Requests the constants from the server and creates the config group structure. * Constructor for ConfigRepositoryService. Requests the constants from the server and creates the config group structure.
*/ */
public constructor(DS: DataStoreService, private constantsService: ConstantsService, private http: HttpClient) { public constructor(DS: DataStoreService, private constantsService: ConstantsService, private http: HttpService) {
super(DS, Config); super(DS, Config);
this.constantsService.get('OpenSlidesConfigVariables').subscribe(constant => { this.constantsService.get('OpenSlidesConfigVariables').subscribe(constant => {
@ -180,12 +181,12 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
/** /**
* Saves a config value. * Saves a config value.
*/ */
public update(config: Partial<Config>, viewConfig: ViewConfig): Observable<Config> { public async update(config: Partial<Config>, viewConfig: ViewConfig): Promise<void> {
const updatedConfig = new Config(); const updatedConfig = new Config();
updatedConfig.patchValues(viewConfig.config); updatedConfig.patchValues(viewConfig.config);
updatedConfig.patchValues(config); updatedConfig.patchValues(config);
// TODO: Use datasendService, if it can switch correctly between put, post and patch // TODO: Use datasendService, if it can switch correctly between put, post and patch
return this.http.put<Config>( await this.http.put(
'rest/' + updatedConfig.collectionString + '/' + updatedConfig.key + '/', 'rest/' + updatedConfig.collectionString + '/' + updatedConfig.key + '/',
updatedConfig updatedConfig
); );
@ -197,7 +198,7 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
* *
* Function exists solely to correctly implement {@link BaseRepository} * Function exists solely to correctly implement {@link BaseRepository}
*/ */
public delete(config: ViewConfig): Observable<Config> { public async delete(config: ViewConfig): Promise<void> {
throw new Error('Config variables cannot be deleted'); throw new Error('Config variables cannot be deleted');
} }
@ -207,7 +208,7 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
* *
* Function exists solely to correctly implement {@link BaseRepository} * Function exists solely to correctly implement {@link BaseRepository}
*/ */
public create(config: Config): Observable<Config> { public async create(config: Config): Promise<Identifiable> {
throw new Error('Config variables cannot be created'); throw new Error('Config variables cannot be created');
} }

View File

@ -7,11 +7,12 @@ import { OperatorService } from 'app/core/services/operator.service';
import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material'; import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material';
import { FormGroup, Validators, FormBuilder } from '@angular/forms'; import { FormGroup, Validators, FormBuilder } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { HttpErrorResponse, HttpClient } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { OpenSlidesService } from '../../../../core/services/openslides.service'; import { OpenSlidesService } from '../../../../core/services/openslides.service';
import { LoginDataService } from '../../../../core/services/login-data.service'; import { LoginDataService } from '../../../../core/services/login-data.service';
import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher'; import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher';
import { HttpService } from '../../../../core/services/http.service';
/** /**
* Login mask component. * Login mask component.
@ -72,7 +73,7 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
private operator: OperatorService, private operator: OperatorService,
private router: Router, private router: Router,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private http: HttpClient, private http: HttpService,
private matSnackBar: MatSnackBar, private matSnackBar: MatSnackBar,
private OpenSlides: OpenSlidesService, private OpenSlides: OpenSlidesService,
private loginDataService: LoginDataService private loginDataService: LoginDataService
@ -89,7 +90,8 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
*/ */
public ngOnInit(): void { public ngOnInit(): void {
// Get the login data. Save information to the login data service // Get the login data. Save information to the login data service
this.http.get<any>(environment.urlPrefix + '/users/login/', {}).subscribe(response => { this.http.get<any>(environment.urlPrefix + '/users/login/').then(
response => {
if (response.info_text) { if (response.info_text) {
this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), { this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), {
duration: 5000 duration: 5000
@ -97,7 +99,11 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
} }
this.loginDataService.setPrivacyPolicy(response.privacy_policy); this.loginDataService.setPrivacyPolicy(response.privacy_policy);
this.loginDataService.setLegalNotice(response.legal_notice); this.loginDataService.setLegalNotice(response.legal_notice);
}); },
() => {
// TODO: Error handling
}
);
} }
public ngOnDestroy(): void { public ngOnDestroy(): void {

View File

@ -4,8 +4,8 @@ import { BaseRepository } from '../../base/base-repository';
import { ViewMediafile } from '../models/view-mediafile'; import { ViewMediafile } from '../models/view-mediafile';
import { Mediafile } from '../../../shared/models/mediafiles/mediafile'; import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
import { User } from '../../../shared/models/users/user'; import { User } from '../../../shared/models/users/user';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository for files * Repository for files
@ -27,7 +27,7 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public update(file: Partial<Mediafile>, viewFile: ViewMediafile): Observable<Mediafile> { public async update(file: Partial<Mediafile>, viewFile: ViewMediafile): Promise<void> {
return null; return null;
} }
@ -36,7 +36,7 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public delete(file: ViewMediafile): Observable<Mediafile> { public async delete(file: ViewMediafile): Promise<void> {
return null; return null;
} }
@ -45,7 +45,7 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
* *
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
*/ */
public create(file: Mediafile): Observable<Mediafile> { public async create(file: Mediafile): Promise<Identifiable> {
return null; return null;
} }

View File

@ -10,8 +10,6 @@ import { ViewCategory } from '../../models/view-category';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Motion } from '../../../../shared/models/motions/motion'; import { Motion } from '../../../../shared/models/motions/motion';
import { SortingListComponent } from '../../../../shared/components/sorting-list/sorting-list.component'; import { SortingListComponent } from '../../../../shared/components/sorting-list/sorting-list.component';
import { MotionRepositoryService } from '../../services/motion-repository.service';
import { ViewMotion } from '../../models/view-motion';
import { PromptService } from 'app/core/services/prompt.service'; import { PromptService } from 'app/core/services/prompt.service';
/** /**
@ -66,7 +64,6 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
protected translate: TranslateService, protected translate: TranslateService,
private repo: CategoryRepositoryService, private repo: CategoryRepositoryService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private motionRepo: MotionRepositoryService,
private promptService: PromptService private promptService: PromptService
) { ) {
super(titleService, translate); super(titleService, translate);
@ -122,12 +119,11 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
/** /**
* Creates a new category. Executed after hitting save. * Creates a new category. Executed after hitting save.
*/ */
public onCreateButton(): void { public async onCreateButton(): Promise<void> {
if (this.createForm.valid) { if (this.createForm.valid) {
this.categoryToCreate.patchValues(this.createForm.value as Category); this.categoryToCreate.patchValues(this.createForm.value as Category);
this.repo.create(this.categoryToCreate).subscribe(resp => { await this.repo.create(this.categoryToCreate)
this.categoryToCreate = null; this.categoryToCreate = null;
});
} }
} }
@ -147,18 +143,17 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
/** /**
* Saves the categories * Saves the categories
*/ */
public onSaveButton(viewCategory: ViewCategory): void { public async onSaveButton(viewCategory: ViewCategory): Promise<void> {
if (this.updateForm.valid) { if (this.updateForm.valid) {
this.repo.update(this.updateForm.value as Partial<Category>, viewCategory).subscribe(resp => { await this.repo.update(this.updateForm.value as Partial<Category>, viewCategory);
this.onCancelButton(); this.onCancelButton();
this.sortDataSource(); this.sortDataSource();
});
} }
// get the sorted motions // get the sorted motions
if (this.sortSelector) { if (this.sortSelector) {
const manuallySortedMotions = this.sortSelector.array as Motion[]; const manuallySortedMotions = this.sortSelector.array as Motion[];
this.repo.updateCategoryNumbering(viewCategory.category, manuallySortedMotions).subscribe(); await this.repo.updateCategoryNumbering(viewCategory.category, manuallySortedMotions);
} }
} }
@ -180,18 +175,11 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
/** /**
* is executed, when the delete button is pressed * is executed, when the delete button is pressed
*/ */
public async onDeleteButton(viewCategory: ViewCategory): Promise<any> { public async onDeleteButton(viewCategory: ViewCategory): Promise<void> {
const content = this.translate.instant('Delete') + ` ${viewCategory.name}?`; const content = this.translate.instant('Delete') + ` ${viewCategory.name}?`;
if (await this.promptService.open('Are you sure?', content)) { if (await this.promptService.open('Are you sure?', content)) {
const motList = this.motionsInCategory(viewCategory.category); await this.repo.delete(viewCategory);
motList.forEach(motion => {
motion.category_id = null;
this.motionRepo.update(motion, new ViewMotion(motion));
});
this.repo.delete(viewCategory).subscribe(resp => {
this.onCancelButton(); this.onCancelButton();
});
} }
} }

View File

@ -109,7 +109,7 @@ export class MotionChangeRecommendationComponent {
}); });
} }
public saveChangeRecommendation(): void { public async saveChangeRecommendation(): Promise<void> {
this.changeReco.updateChangeReco( this.changeReco.updateChangeReco(
this.contentForm.controls.diffType.value, this.contentForm.controls.diffType.value,
this.contentForm.controls.text.value, this.contentForm.controls.text.value,
@ -117,21 +117,13 @@ export class MotionChangeRecommendationComponent {
); );
if (this.newReco) { if (this.newReco) {
this.repo.createByViewModel(this.changeReco).subscribe(response => { await this.repo.createByViewModel(this.changeReco);
if (response.id) { this.dialogRef.close();
this.dialogRef.close(response); // @TODO Show an error message
} else { } else {
await this.repo.update(this.changeReco.changeRecommendation, this.changeReco);
this.dialogRef.close();
// @TODO Show an error message // @TODO Show an error message
} }
});
} else {
this.repo.update(this.changeReco.changeRecommendation, this.changeReco).subscribe(response => {
if (response.id) {
this.dialogRef.close(response);
} else {
// @TODO Show an error message
}
});
}
} }
} }

View File

@ -111,12 +111,11 @@ export class MotionCommentSectionListComponent extends BaseComponent implements
} }
} }
public create(): void { public async create(): Promise<void> {
if (this.createForm.valid) { if (this.createForm.valid) {
this.commentSectionToCreate.patchValues(this.createForm.value as MotionCommentSection); this.commentSectionToCreate.patchValues(this.createForm.value as MotionCommentSection);
this.repo.create(this.commentSectionToCreate).subscribe(resp => { await this.repo.create(this.commentSectionToCreate);
this.commentSectionToCreate = null; this.commentSectionToCreate = null;
});
} }
} }
@ -137,23 +136,21 @@ export class MotionCommentSectionListComponent extends BaseComponent implements
/** /**
* Saves the categories * Saves the categories
*/ */
public onSaveButton(viewSection: ViewMotionCommentSection): void { public async onSaveButton(viewSection: ViewMotionCommentSection): Promise<void> {
if (this.updateForm.valid) { if (this.updateForm.valid) {
this.repo.update(this.updateForm.value as Partial<MotionCommentSection>, viewSection).subscribe(resp => { await this.repo.update(this.updateForm.value as Partial<MotionCommentSection>, viewSection);
this.openId = this.editId = null; this.openId = this.editId = null;
});
} }
} }
/** /**
* is executed, when the delete button is pressed * is executed, when the delete button is pressed
*/ */
public async onDeleteButton(viewSection: ViewMotionCommentSection): Promise<any> { public async onDeleteButton(viewSection: ViewMotionCommentSection): Promise<void> {
const content = this.translate.instant('Delete') + ` ${viewSection.name}?`; const content = this.translate.instant('Delete') + ` ${viewSection.name}?`;
if (await this.promptService.open('Are you sure?', content)) { if (await this.promptService.open('Are you sure?', content)) {
this.repo.delete(viewSection).subscribe(resp => { await this.repo.delete(viewSection);
this.openId = this.editId = null; this.openId = this.editId = null;
});
} }
} }

View File

@ -170,12 +170,12 @@ export class MotionDetailDiffComponent implements AfterViewInit {
* @param {ViewChangeReco} change * @param {ViewChangeReco} change
* @param {string} value * @param {string} value
*/ */
public setAcceptanceValue(change: ViewChangeReco, value: string): void { public async setAcceptanceValue(change: ViewChangeReco, value: string): Promise<void> {
if (value === 'accepted') { if (value === 'accepted') {
this.recoRepo.setAccepted(change).subscribe(); // Subscribe to trigger HTTP request await this.recoRepo.setAccepted(change);
} }
if (value === 'rejected') { if (value === 'rejected') {
this.recoRepo.setRejected(change).subscribe(); // Subscribe to trigger HTTP request await this.recoRepo.setRejected(change);
} }
} }
@ -185,8 +185,8 @@ export class MotionDetailDiffComponent implements AfterViewInit {
* @param {ViewChangeReco} change * @param {ViewChangeReco} change
* @param {boolean} internal * @param {boolean} internal
*/ */
public setInternal(change: ViewChangeReco, internal: boolean): void { public async setInternal(change: ViewChangeReco, internal: boolean): Promise<void> {
this.recoRepo.setInternal(change, internal).subscribe(); // Subscribe to trigger HTTP request await this.recoRepo.setInternal(change, internal);
} }
/** /**
@ -196,10 +196,10 @@ export class MotionDetailDiffComponent implements AfterViewInit {
* @param {ViewChangeReco} reco * @param {ViewChangeReco} reco
* @param {MouseEvent} $event * @param {MouseEvent} $event
*/ */
public deleteChangeRecommendation(reco: ViewChangeReco, $event: MouseEvent): void { public async deleteChangeRecommendation(reco: ViewChangeReco, $event: MouseEvent): Promise<void> {
this.recoRepo.delete(reco).subscribe(); // Subscribe to trigger HTTP request
$event.stopPropagation(); $event.stopPropagation();
$event.preventDefault(); $event.preventDefault();
await this.recoRepo.delete(reco);
} }
/** /**

View File

@ -264,40 +264,20 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
* *
* TODO: state is not yet saved. Need a special "put" command. Repo should handle this. * TODO: state is not yet saved. Need a special "put" command. Repo should handle this.
*/ */
public saveMotion(): void { public async saveMotion(): Promise<void> {
const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value }; const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value };
const fromForm = new Motion(); const fromForm = new Motion();
fromForm.deserialize(newMotionValues); fromForm.deserialize(newMotionValues);
if (this.newMotion) { if (this.newMotion) {
this.repo.create(fromForm).subscribe(response => { const response = await this.repo.create(fromForm);
if (response.id) {
this.router.navigate(['./motions/' + response.id]); this.router.navigate(['./motions/' + response.id]);
}
});
} else { } else {
this.repo.update(fromForm, this.motionCopy).subscribe(response => { await this.repo.update(fromForm, this.motionCopy);
// if the motion was successfully updated, change the edit mode. // if the motion was successfully updated, change the edit mode.
// TODO: Show errors if there appear here
if (response.id) {
this.editMotion = false; this.editMotion = false;
} // TODO: Show errors if there appear here
});
// TODO: Document and evaluate if this actually does what it is supposed to do
if (fromForm.category_id) {
const catOfFormMotion = this.categoryRepo.getCategoryByID(fromForm.category_id);
const motionsWithSameCat = this.categoryRepo.getMotionsOfCategory(catOfFormMotion);
if (!motionsWithSameCat.includes(fromForm)) {
motionsWithSameCat.push(fromForm);
this.categoryRepo.updateCategoryNumbering(
this.categoryRepo.getCategoryByID(fromForm.category_id),
motionsWithSameCat
);
}
}
} }
} }
@ -329,7 +309,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
* TODO: Repo should handle * TODO: Repo should handle
*/ */
public deleteMotionButton(): void { public deleteMotionButton(): void {
this.repo.delete(this.motion).subscribe(answer => { this.repo.delete(this.motion).then(() => {
this.router.navigate(['./motions/']); this.router.navigate(['./motions/']);
}); });
const motList = this.categoryRepo.getMotionsOfCategory(this.motion.category); const motList = this.categoryRepo.getMotionsOfCategory(this.motion.category);

View File

@ -85,12 +85,11 @@ export class StatuteParagraphListComponent extends BaseComponent implements OnIn
} }
} }
public create(): void { public async create(): Promise<void> {
if (this.createForm.valid) { if (this.createForm.valid) {
this.statuteParagraphToCreate.patchValues(this.createForm.value as StatuteParagraph); this.statuteParagraphToCreate.patchValues(this.createForm.value as StatuteParagraph);
this.repo.create(this.statuteParagraphToCreate).subscribe(resp => { await this.repo.create(this.statuteParagraphToCreate);
this.statuteParagraphToCreate = null; this.statuteParagraphToCreate = null;
});
} }
} }
@ -110,25 +109,21 @@ export class StatuteParagraphListComponent extends BaseComponent implements OnIn
/** /**
* Saves the statute paragrpah * Saves the statute paragrpah
*/ */
public onSaveButton(viewStatuteParagraph: ViewStatuteParagraph): void { public async onSaveButton(viewStatuteParagraph: ViewStatuteParagraph): Promise<void> {
if (this.updateForm.valid) { if (this.updateForm.valid) {
this.repo await this.repo.update(this.updateForm.value as Partial<StatuteParagraph>, viewStatuteParagraph);
.update(this.updateForm.value as Partial<StatuteParagraph>, viewStatuteParagraph)
.subscribe(resp => {
this.openId = this.editId = null; this.openId = this.editId = null;
});
} }
} }
/** /**
* is executed, when the delete button is pressed * is executed, when the delete button is pressed
*/ */
public async onDeleteButton(viewStatuteParagraph: ViewStatuteParagraph): Promise<any> { public async onDeleteButton(viewStatuteParagraph: ViewStatuteParagraph): Promise<void> {
const content = this.translate.instant('Delete') + ` ${viewStatuteParagraph.title}?`; const content = this.translate.instant('Delete') + ` ${viewStatuteParagraph.title}?`;
if (await this.promptService.open('Are you sure?', content)) { if (await this.promptService.open('Are you sure?', content)) {
this.repo.delete(viewStatuteParagraph).subscribe(resp => { await this.repo.delete(viewStatuteParagraph);
this.openId = this.editId = null; this.openId = this.editId = null;
});
} }
} }

View File

@ -2,12 +2,12 @@ import { Injectable } from '@angular/core';
import { Category } from '../../../shared/models/motions/category'; import { Category } from '../../../shared/models/motions/category';
import { ViewCategory } from '../models/view-category'; import { ViewCategory } from '../models/view-category';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { Motion } from '../../../shared/models/motions/motion'; import { Motion } from '../../../shared/models/motions/motion';
import { CategoryNumbering } from '../models/category-numbering'; import { CategoryNumbering } from '../models/category-numbering';
import { HttpService, HTTPMethod } from '../../../core/services/http.service'; import { HttpService } from '../../../core/services/http.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for Categories * Repository Services for Categories
@ -41,11 +41,11 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
return new ViewCategory(category); return new ViewCategory(category);
} }
public create(newCategory: Category): Observable<any> { public async create(newCategory: Category): Promise<Identifiable> {
return this.dataSend.createModel(newCategory); return await this.dataSend.createModel(newCategory);
} }
public update(category: Partial<Category>, viewCategory?: ViewCategory): Observable<any> { public async update(category: Partial<Category>, viewCategory: ViewCategory): Promise<void> {
let updateCategory: Category; let updateCategory: Category;
if (viewCategory) { if (viewCategory) {
updateCategory = viewCategory.category; updateCategory = viewCategory.category;
@ -53,12 +53,12 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
updateCategory = new Category(); updateCategory = new Category();
} }
updateCategory.patchValues(category); updateCategory.patchValues(category);
return this.dataSend.updateModel(updateCategory, HTTPMethod.PUT); await this.dataSend.updateModel(updateCategory);
} }
public delete(viewCategory: ViewCategory): Observable<any> { public async delete(viewCategory: ViewCategory): Promise<void> {
const category = viewCategory.category; const category = viewCategory.category;
return this.dataSend.deleteModel(category); await this.dataSend.deleteModel(category);
} }
/** /**
@ -91,10 +91,10 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
* @param category the category it should be updated in * @param category the category it should be updated in
* @param motionList the list of motions on this category * @param motionList the list of motions on this category
*/ */
public updateCategoryNumbering(category: Category, motionList: Motion[]): Observable<object> { public async updateCategoryNumbering(category: Category, motionList: Motion[]): Promise<void> {
const categoryNumbering = new CategoryNumbering(); const categoryNumbering = new CategoryNumbering();
categoryNumbering.setMotions(motionList); categoryNumbering.setMotions(motionList);
return this.sentCategoryNumbering(category, categoryNumbering); await this.sentCategoryNumbering(category, categoryNumbering);
} }
/** /**
@ -102,8 +102,8 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
* *
* @return Observable from * @return Observable from
*/ */
protected sentCategoryNumbering(category: Category, categoryNumbering: CategoryNumbering): Observable<object> { protected async sentCategoryNumbering(category: Category, categoryNumbering: CategoryNumbering): Promise<void> {
const collectionString = 'rest/motions/category/' + category.id + '/numbering/'; const collectionString = 'rest/motions/category/' + category.id + '/numbering/';
return this.httpService.create(collectionString, categoryNumbering); await this.httpService.post(collectionString, categoryNumbering);
} }
} }

View File

@ -10,7 +10,7 @@ import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco'; import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
import { ViewChangeReco } from '../models/view-change-reco'; import { ViewChangeReco } from '../models/view-change-reco';
import { HTTPMethod } from 'app/core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for change recommendations * Repository Services for change recommendations
@ -44,8 +44,8 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* *
* @param {MotionChangeReco} changeReco * @param {MotionChangeReco} changeReco
*/ */
public create(changeReco: MotionChangeReco): Observable<MotionChangeReco> { public async create(changeReco: MotionChangeReco): Promise<Identifiable> {
return this.dataSend.createModel(changeReco) as Observable<MotionChangeReco>; return await this.dataSend.createModel(changeReco);
} }
/** /**
@ -53,13 +53,13 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* change recommendation view object is returned (as an observable). * change recommendation view object is returned (as an observable).
* *
* @param {ViewChangeReco} view * @param {ViewChangeReco} view
* @deprecated Will not work with PR #3928. There will just be the id as response to create requests.
* Two possibilities: Make a server change to still retrieve the created object or you have to wait for the
* correct autoupdate.
*/ */
public createByViewModel(view: ViewChangeReco): Observable<ViewChangeReco> { public async createByViewModel(view: ViewChangeReco): Promise<Identifiable> {
return this.create(view.changeRecommendation).pipe( return await this.dataSend.createModel(view.changeRecommendation);
map((changeReco: MotionChangeReco) => { // return new ViewChangeReco(cr);
return new ViewChangeReco(changeReco);
})
);
} }
/** /**
@ -78,8 +78,8 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* to {@link DataSendService} * to {@link DataSendService}
* @param {ViewChangeReco} viewModel * @param {ViewChangeReco} viewModel
*/ */
public delete(viewModel: ViewChangeReco): Observable<MotionChangeReco> { public async delete(viewModel: ViewChangeReco): Promise<void> {
return this.dataSend.deleteModel(viewModel.changeRecommendation) as Observable<MotionChangeReco>; await this.dataSend.deleteModel(viewModel.changeRecommendation);
} }
/** /**
@ -91,10 +91,10 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* @param {Partial<MotionChangeReco>} update the form data containing the update values * @param {Partial<MotionChangeReco>} update the form data containing the update values
* @param {ViewChangeReco} viewModel The View Change Recommendation. If not present, a new motion will be created * @param {ViewChangeReco} viewModel The View Change Recommendation. If not present, a new motion will be created
*/ */
public update(update: Partial<MotionChangeReco>, viewModel: ViewChangeReco): Observable<MotionChangeReco> { public async update(update: Partial<MotionChangeReco>, viewModel: ViewChangeReco): Promise<void> {
const changeReco = viewModel.changeRecommendation; const changeReco = viewModel.changeRecommendation;
changeReco.patchValues(update); changeReco.patchValues(update);
return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable<MotionChangeReco>; await this.dataSend.partialUpdateModel(changeReco);
} }
/** /**
@ -113,12 +113,12 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* *
* @param {ViewChangeReco} change * @param {ViewChangeReco} change
*/ */
public setAccepted(change: ViewChangeReco): Observable<MotionChangeReco> { public async setAccepted(change: ViewChangeReco): Promise<void> {
const changeReco = change.changeRecommendation; const changeReco = change.changeRecommendation;
changeReco.patchValues({ changeReco.patchValues({
rejected: false rejected: false
}); });
return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable<MotionChangeReco>; await this.dataSend.partialUpdateModel(changeReco);
} }
/** /**
@ -126,12 +126,12 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* *
* @param {ViewChangeReco} change * @param {ViewChangeReco} change
*/ */
public setRejected(change: ViewChangeReco): Observable<MotionChangeReco> { public async setRejected(change: ViewChangeReco): Promise<void> {
const changeReco = change.changeRecommendation; const changeReco = change.changeRecommendation;
changeReco.patchValues({ changeReco.patchValues({
rejected: true rejected: true
}); });
return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable<MotionChangeReco>; await this.dataSend.partialUpdateModel(changeReco);
} }
/** /**
@ -140,11 +140,11 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<ViewCh
* @param {ViewChangeReco} change * @param {ViewChangeReco} change
* @param {boolean} internal * @param {boolean} internal
*/ */
public setInternal(change: ViewChangeReco, internal: boolean): Observable<MotionChangeReco> { public async setInternal(change: ViewChangeReco, internal: boolean): Promise<void> {
const changeReco = change.changeRecommendation; const changeReco = change.changeRecommendation;
changeReco.patchValues({ changeReco.patchValues({
internal: internal internal: internal
}); });
return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable<MotionChangeReco>; await this.dataSend.partialUpdateModel(changeReco);
} }
} }

View File

@ -1,12 +1,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { ViewMotionCommentSection } from '../models/view-motion-comment-section'; import { ViewMotionCommentSection } from '../models/view-motion-comment-section';
import { MotionCommentSection } from '../../../shared/models/motions/motion-comment-section'; import { MotionCommentSection } from '../../../shared/models/motions/motion-comment-section';
import { Group } from '../../../shared/models/users/group'; import { Group } from '../../../shared/models/users/group';
import { HTTPMethod } from 'app/core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for Categories * Repository Services for Categories
@ -41,11 +40,11 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
return new ViewMotionCommentSection(section, read_groups, write_groups); return new ViewMotionCommentSection(section, read_groups, write_groups);
} }
public create(section: MotionCommentSection): Observable<any> { public async create(section: MotionCommentSection): Promise<Identifiable> {
return this.dataSend.createModel(section); return await this.dataSend.createModel(section);
} }
public update(section: Partial<MotionCommentSection>, viewSection?: ViewMotionCommentSection): Observable<any> { public async update(section: Partial<MotionCommentSection>, viewSection?: ViewMotionCommentSection): Promise<void> {
let updateSection: MotionCommentSection; let updateSection: MotionCommentSection;
if (viewSection) { if (viewSection) {
updateSection = viewSection.section; updateSection = viewSection.section;
@ -53,10 +52,10 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
updateSection = new MotionCommentSection(); updateSection = new MotionCommentSection();
} }
updateSection.patchValues(section); updateSection.patchValues(section);
return this.dataSend.updateModel(updateSection, HTTPMethod.PUT); await this.dataSend.updateModel(updateSection);
} }
public delete(viewSection: ViewMotionCommentSection): Observable<any> { public async delete(viewSection: ViewMotionCommentSection): Promise<void> {
return this.dataSend.deleteModel(viewSection.section); await this.dataSend.deleteModel(viewSection.section);
} }
} }

View File

@ -7,7 +7,6 @@ import { Category } from '../../../shared/models/motions/category';
import { Workflow } from '../../../shared/models/motions/workflow'; import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state'; import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { ChangeRecoMode, ViewMotion } from '../models/view-motion'; import { ChangeRecoMode, ViewMotion } from '../models/view-motion';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { LinenumberingService } from './linenumbering.service'; import { LinenumberingService } from './linenumbering.service';
@ -15,7 +14,7 @@ import { DiffService, LineRange, ModificationType } from './diff.service';
import { ViewChangeReco } from '../models/view-change-reco'; import { ViewChangeReco } from '../models/view-change-reco';
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco'; import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
import { ViewUnifiedChange } from '../models/view-unified-change'; import { ViewUnifiedChange } from '../models/view-unified-change';
import { HTTPMethod } from '../../../core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for motions (and potentially categories) * Repository Services for motions (and potentially categories)
@ -79,11 +78,11 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
* @param viewMotion The View Motion. If not present, a new motion will be created * @param viewMotion The View Motion. If not present, a new motion will be created
* TODO: Remove the viewMotion and make it actually distignuishable from save() * TODO: Remove the viewMotion and make it actually distignuishable from save()
*/ */
public create(motion: Motion): Observable<any> { public async create(motion: Motion): Promise<Identifiable> {
if (!motion.supporters_id) { if (!motion.supporters_id) {
delete motion.supporters_id; delete motion.supporters_id;
} }
return this.dataSend.createModel(motion); return await this.dataSend.createModel(motion);
} }
/** /**
@ -95,10 +94,10 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
* @param update the form data containing the update values * @param update the form data containing the update values
* @param viewMotion The View Motion. If not present, a new motion will be created * @param viewMotion The View Motion. If not present, a new motion will be created
*/ */
public update(update: Partial<Motion>, viewMotion: ViewMotion): Observable<any> { public async update(update: Partial<Motion>, viewMotion: ViewMotion): Promise<void> {
const motion = viewMotion.motion; const motion = viewMotion.motion;
motion.patchValues(update); motion.patchValues(update);
return this.dataSend.updateModel(motion, HTTPMethod.PATCH); await this.dataSend.partialUpdateModel(motion);
} }
/** /**
@ -108,8 +107,8 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
* to {@link DataSendService} * to {@link DataSendService}
* @param viewMotion * @param viewMotion
*/ */
public delete(viewMotion: ViewMotion): Observable<any> { public async delete(viewMotion: ViewMotion): Promise<void> {
return this.dataSend.deleteModel(viewMotion.motion); await this.dataSend.deleteModel(viewMotion.motion);
} }
/** /**

View File

@ -1,11 +1,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { ViewStatuteParagraph } from '../models/view-statute-paragraph'; import { ViewStatuteParagraph } from '../models/view-statute-paragraph';
import { StatuteParagraph } from '../../../shared/models/motions/statute-paragraph'; import { StatuteParagraph } from '../../../shared/models/motions/statute-paragraph';
import { HTTPMethod } from 'app/core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for statute paragraphs * Repository Services for statute paragraphs
@ -32,20 +31,20 @@ export class StatuteParagraphRepositoryService extends BaseRepository<ViewStatut
return new ViewStatuteParagraph(statuteParagraph); return new ViewStatuteParagraph(statuteParagraph);
} }
public create(statuteParagraph: StatuteParagraph): Observable<any> { public async create(statuteParagraph: StatuteParagraph): Promise<Identifiable> {
return this.dataSend.createModel(statuteParagraph); return await this.dataSend.createModel(statuteParagraph);
} }
public update( public async update(
statuteParagraph: Partial<StatuteParagraph>, statuteParagraph: Partial<StatuteParagraph>,
viewStatuteParagraph: ViewStatuteParagraph viewStatuteParagraph: ViewStatuteParagraph
): Observable<any> { ): Promise<void> {
const updateParagraph = viewStatuteParagraph.statuteParagraph; const updateParagraph = viewStatuteParagraph.statuteParagraph;
updateParagraph.patchValues(statuteParagraph); updateParagraph.patchValues(statuteParagraph);
return this.dataSend.updateModel(updateParagraph, HTTPMethod.PUT); await this.dataSend.updateModel(updateParagraph);
} }
public delete(viewStatuteParagraph: ViewStatuteParagraph): Observable<any> { public async delete(viewStatuteParagraph: ViewStatuteParagraph): Promise<void> {
return this.dataSend.deleteModel(viewStatuteParagraph.statuteParagraph); await this.dataSend.deleteModel(viewStatuteParagraph.statuteParagraph);
} }
} }

View File

@ -1,7 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TagListComponent } from './tag-list.component'; import { TagListComponent } from './tag-list.component';
import { E2EImportsModule } from '../../../../e2e-imports.module'; import { E2EImportsModule } from 'e2e-imports.module';
describe('TagListComponent', () => { describe('TagListComponent', () => {
let component: TagListComponent; let component: TagListComponent;

View File

@ -1,12 +1,12 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { Tag } from '../../../shared/models/core/tag'; import { Tag } from '../../../../shared/models/core/tag';
import { ListViewBaseComponent } from '../../base/list-view-base'; import { ListViewBaseComponent } from '../../../base/list-view-base';
import { TagRepositoryService } from '../services/tag-repository.service'; import { TagRepositoryService } from '../../services/tag-repository.service';
import { ViewTag } from '../models/view-tag'; import { ViewTag } from '../../models/view-tag';
import { FormGroup, FormControl, Validators } from '@angular/forms'; import { FormGroup, FormControl, Validators } from '@angular/forms';
import { PromptService } from '../../../core/services/prompt.service'; import { PromptService } from '../../../../core/services/prompt.service';
/** /**
* Listview for the complete lsit of available Tags * Listview for the complete lsit of available Tags
@ -70,42 +70,36 @@ export class TagListComponent extends ListViewBaseComponent<ViewTag> implements
/** /**
* Saves a newly created tag. * Saves a newly created tag.
*/ */
public submitNewTag(): void { public async submitNewTag(): Promise<void> {
if (this.tagForm.value && this.tagForm.valid) { if (!this.tagForm.value || !this.tagForm.valid) {
this.repo.create(this.tagForm.value).subscribe(response => { return;
if (response) { }
await this.repo.create(this.tagForm.value);
this.tagForm.reset(); this.tagForm.reset();
this.cancelEditing(); this.cancelEditing();
} }
});
}
}
/** /**
* Saves an edited tag. * Saves an edited tag.
*/ */
public submitEditedTag(): void { public async submitEditedTag(): Promise<void> {
if (this.tagForm.value && this.tagForm.valid) { if (!this.tagForm.value || !this.tagForm.valid) {
return;
}
const updateData = new Tag({ name: this.tagForm.value.name }); const updateData = new Tag({ name: this.tagForm.value.name });
this.repo.update(updateData, this.selectedTag).subscribe(response => { await this.repo.update(updateData, this.selectedTag);
if (response) {
this.cancelEditing(); this.cancelEditing();
} }
});
}
}
/** /**
* Deletes the selected Tag after a successful confirmation. * Deletes the selected Tag after a successful confirmation.
* @async
*/ */
public async deleteSelectedTag(): Promise<any> { public async deleteSelectedTag(): Promise<void> {
const content = this.translate.instant('Delete') + ` ${this.selectedTag.name}?`; const content = this.translate.instant('Delete') + ` ${this.selectedTag.name}?`;
if (await this.promptService.open(this.translate.instant('Are you sure?'), content)) { if (await this.promptService.open(this.translate.instant('Are you sure?'), content)) {
this.repo.delete(this.selectedTag).subscribe(response => { await this.repo.delete(this.selectedTag);
this.cancelEditing(); this.cancelEditing();
});
} }
} }

View File

@ -2,10 +2,9 @@ import { Injectable } from '@angular/core';
import { Tag } from '../../../shared/models/core/tag'; import { Tag } from '../../../shared/models/core/tag';
import { ViewTag } from '../models/view-tag'; import { ViewTag } from '../models/view-tag';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
import { HTTPMethod } from 'app/core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository Services for Tags * Repository Services for Tags
@ -35,20 +34,20 @@ export class TagRepositoryService extends BaseRepository<ViewTag, Tag> {
return new ViewTag(tag); return new ViewTag(tag);
} }
public create(update: Tag): Observable<any> { public async create(update: Tag): Promise<Identifiable> {
const newTag = new Tag(); const newTag = new Tag();
newTag.patchValues(update); newTag.patchValues(update);
return this.dataSend.createModel(newTag); return await this.dataSend.createModel(newTag);
} }
public update(update: Partial<Tag>, viewTag: ViewTag): Observable<any> { public async update(update: Partial<Tag>, viewTag: ViewTag): Promise<void> {
const updateTag = new Tag(); const updateTag = new Tag();
updateTag.patchValues(viewTag.tag); updateTag.patchValues(viewTag.tag);
updateTag.patchValues(update); updateTag.patchValues(update);
return this.dataSend.updateModel(updateTag, HTTPMethod.PUT); await this.dataSend.updateModel(updateTag);
} }
public delete(viewTag: ViewTag): Observable<any> { public async delete(viewTag: ViewTag): Promise<void> {
return this.dataSend.deleteModel(viewTag.tag); await this.dataSend.deleteModel(viewTag.tag);
} }
} }

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule } from '@angular/router';
import { TagListComponent } from './components/tag-list.component'; import { TagListComponent } from './components/tag-list/tag-list.component';
const routes: Routes = [{ path: '', component: TagListComponent }]; const routes: Routes = [{ path: '', component: TagListComponent }];

View File

@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
import { TagRoutingModule } from './tag-routing.module'; import { TagRoutingModule } from './tag-routing.module';
import { SharedModule } from '../../shared/shared.module'; import { SharedModule } from '../../shared/shared.module';
import { TagListComponent } from './components/tag-list.component'; import { TagListComponent } from './components/tag-list/tag-list.component';
@NgModule({ @NgModule({
imports: [CommonModule, TagRoutingModule, SharedModule], imports: [CommonModule, TagRoutingModule, SharedModule],

View File

@ -88,38 +88,35 @@ export class GroupListComponent extends BaseComponent implements OnInit {
* Saves a newly created group. * Saves a newly created group.
* @param form form data given by the group * @param form form data given by the group
*/ */
public submitNewGroup(): void { public async submitNewGroup(): Promise<void> {
if (this.groupForm.value && this.groupForm.valid) { if (!this.groupForm.value || !this.groupForm.valid) {
this.repo.create(this.groupForm.value).subscribe(response => { return;
if (response) { }
await this.repo.create(this.groupForm.value);
this.groupForm.reset(); this.groupForm.reset();
this.cancelEditing(); this.cancelEditing();
} }
});
}
}
/** /**
* Saves an edited group. * Saves an edited group.
* @param form form data given by the group * @param form form data given by the group
*/ */
public submitEditedGroup(): void { public async submitEditedGroup(): Promise<void> {
if (this.groupForm.value && this.groupForm.valid) { if (!this.groupForm.value || !this.groupForm.valid) {
return;
}
const updateData = new Group({ name: this.groupForm.value.name }); const updateData = new Group({ name: this.groupForm.value.name });
this.repo.update(updateData, this.selectedGroup).subscribe(response => { await this.repo.update(updateData, this.selectedGroup);
if (response) {
this.cancelEditing(); this.cancelEditing();
} }
});
}
}
/** /**
* Deletes the selected Group * Deletes the selected Group
*/ */
public deleteSelectedGroup(): void { public async deleteSelectedGroup(): Promise<void> {
this.repo.delete(this.selectedGroup).subscribe(response => this.cancelEditing()); await this.repo.delete(this.selectedGroup)
this.cancelEditing();
} }
/** /**
@ -136,9 +133,9 @@ export class GroupListComponent extends BaseComponent implements OnInit {
* @param group * @param group
* @param perm * @param perm
*/ */
public togglePerm(viewGroup: ViewGroup, perm: string): void { public async togglePerm(viewGroup: ViewGroup, perm: string): Promise<void> {
const updateData = new Group({ permissions: viewGroup.getAlteredPermissions(perm) }); const updateData = new Group({ permissions: viewGroup.getAlteredPermissions(perm) });
this.repo.update(updateData, viewGroup).subscribe(); await this.repo.update(updateData, viewGroup);
} }
/** /**

View File

@ -253,23 +253,17 @@ export class UserDetailComponent implements OnInit {
/** /**
* Save / Submit a user * Save / Submit a user
*/ */
public saveUser(): void { public async saveUser(): Promise<void> {
if (this.newUser) { if (this.newUser) {
this.repo.create(this.personalInfoForm.value).subscribe( const response = await this.repo.create(this.personalInfoForm.value);
response => {
this.newUser = false; this.newUser = false;
this.router.navigate([`./users/${response.id}`]); this.router.navigate([`./users/${response.id}`]);
},
error => console.error('Creation of the user failed: ', error.error)
);
} else { } else {
this.repo.update(this.personalInfoForm.value, this.user).subscribe( // TODO (Issue #3962): We need a waiting-State, so if autoupdates come before the response,
response => { // the user is also updated.
await this.repo.update(this.personalInfoForm.value, this.user);
this.setEditMode(false); this.setEditMode(false);
this.loadViewUser(response.id); this.loadViewUser(this.user.id);
},
error => console.error('Update of the user failed: ', error.error)
);
} }
} }
@ -290,10 +284,9 @@ export class UserDetailComponent implements OnInit {
/** /**
* click on the delete user button * click on the delete user button
*/ */
public deleteUserButton(): void { public async deleteUserButton(): Promise<void> {
this.repo.delete(this.user).subscribe(response => { await this.repo.delete(this.user);
this.router.navigate(['./users/']); this.router.navigate(['./users/']);
});
} }
/** /**

View File

@ -1,5 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { ViewGroup } from '../models/view-group'; import { ViewGroup } from '../models/view-group';
import { BaseRepository } from '../../base/base-repository'; import { BaseRepository } from '../../base/base-repository';
@ -7,7 +6,7 @@ import { Group } from '../../../shared/models/users/group';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { ConstantsService } from '../../../core/services/constants.service'; import { ConstantsService } from '../../../core/services/constants.service';
import { HTTPMethod } from 'app/core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Set rules to define the shape of an app permission * Set rules to define the shape of an app permission
@ -109,10 +108,10 @@ export class GroupRepositoryService extends BaseRepository<ViewGroup, Group> {
* *
* @param groupData form value. Usually not yet a real user * @param groupData form value. Usually not yet a real user
*/ */
public create(groupData: Partial<Group>): Observable<any> { public async create(groupData: Partial<Group>): Promise<Identifiable> {
const newGroup = new Group(); const newGroup = new Group();
newGroup.patchValues(groupData); newGroup.patchValues(groupData);
return this.dataSend.createModel(newGroup); return await this.dataSend.createModel(newGroup);
} }
/** /**
@ -121,18 +120,18 @@ export class GroupRepositoryService extends BaseRepository<ViewGroup, Group> {
* @param permission the new permission * @param permission the new permission
* @param viewGroup the selected Group * @param viewGroup the selected Group
*/ */
public update(groupData: Partial<Group>, viewGroup: ViewGroup): Observable<any> { public async update(groupData: Partial<Group>, viewGroup: ViewGroup): Promise<void> {
const updateGroup = new Group(); const updateGroup = new Group();
updateGroup.patchValues(viewGroup.group); updateGroup.patchValues(viewGroup.group);
updateGroup.patchValues(groupData); updateGroup.patchValues(groupData);
return this.dataSend.updateModel(updateGroup, HTTPMethod.PUT); await this.dataSend.updateModel(updateGroup);
} }
/** /**
* Deletes a given group * Deletes a given group
*/ */
public delete(viewGroup: ViewGroup): Observable<any> { public async delete(viewGroup: ViewGroup): Promise<void> {
return this.dataSend.deleteModel(viewGroup.group); await this.dataSend.deleteModel(viewGroup.group);
} }
public createViewModel(group: Group): ViewGroup { public createViewModel(group: Group): ViewGroup {

View File

@ -4,10 +4,9 @@ import { BaseRepository } from '../../base/base-repository';
import { ViewUser } from '../models/view-user'; import { ViewUser } from '../models/view-user';
import { User } from '../../../shared/models/users/user'; import { User } from '../../../shared/models/users/user';
import { Group } from '../../../shared/models/users/group'; import { Group } from '../../../shared/models/users/group';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
import { DataSendService } from '../../../core/services/data-send.service'; import { DataSendService } from '../../../core/services/data-send.service';
import { HTTPMethod } from '../../../core/services/http.service'; import { Identifiable } from '../../../shared/models/base/identifiable';
/** /**
* Repository service for users * Repository service for users
@ -31,7 +30,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
* @param update the forms values * @param update the forms values
* @param viewUser * @param viewUser
*/ */
public update(update: Partial<User>, viewUser: ViewUser): Observable<any> { public async update(update: Partial<User>, viewUser: ViewUser): Promise<void> {
const updateUser = new User(); const updateUser = new User();
// copy the ViewUser to avoid manipulation of parameters // copy the ViewUser to avoid manipulation of parameters
updateUser.patchValues(viewUser.user); updateUser.patchValues(viewUser.user);
@ -43,14 +42,14 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
updateUser.username = viewUser.username; updateUser.username = viewUser.username;
} }
return this.dataSend.updateModel(updateUser, HTTPMethod.PUT); await this.dataSend.updateModel(updateUser);
} }
/** /**
* Deletes a given user * Deletes a given user
*/ */
public delete(viewUser: ViewUser): Observable<any> { public async delete(viewUser: ViewUser): Promise<void> {
return this.dataSend.deleteModel(viewUser.user); await this.dataSend.deleteModel(viewUser.user);
} }
/** /**
@ -59,7 +58,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
* TODO: used over not-yet-existing detail view * TODO: used over not-yet-existing detail view
* @param userData blank form value. Usually not yet a real user * @param userData blank form value. Usually not yet a real user
*/ */
public create(userData: Partial<User>): Observable<any> { public async create(userData: Partial<User>): Promise<Identifiable> {
const newUser = new User(); const newUser = new User();
// collectionString of userData is still empty // collectionString of userData is still empty
newUser.patchValues(userData); newUser.patchValues(userData);
@ -73,7 +72,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
} }
}); });
return this.dataSend.createModel(newUser); return await this.dataSend.createModel(newUser);
} }
public createViewModel(user: User): ViewUser { public createViewModel(user: User): ViewUser {