From 060e68844dff26e2385ac2f75c4fddacf7385b26 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Fri, 26 Oct 2018 11:19:05 +0200 Subject: [PATCH] Refine the HTTP Service. --- client/src/app/core/pruning-loader.ts | 3 +- .../app/core/services/data-send.service.ts | 48 +++--- client/src/app/core/services/http.service.ts | 141 ++++++++---------- .../legal-notice-content.component.ts | 15 +- .../services/agenda-repository.service.ts | 8 +- .../services/assignment-repository.service.ts | 8 +- client/src/app/site/base/base-repository.ts | 7 +- .../config-field/config-field.component.ts | 24 +-- .../services/config-repository.service.ts | 13 +- .../login-mask/login-mask.component.ts | 26 ++-- .../services/mediafile-repository.service.ts | 8 +- .../category-list/category-list.component.ts | 34 ++--- .../motion-change-recommendation.component.ts | 22 +-- .../motion-comment-section-list.component.ts | 21 ++- .../motion-detail-diff.component.ts | 14 +- .../motion-detail/motion-detail.component.ts | 36 +---- .../statute-paragraph-list.component.ts | 23 ++- .../services/category-repository.service.ts | 24 +-- ...hange-recommendation-repository.service.ts | 38 ++--- ...tion-comment-section-repository.service.ts | 15 +- .../services/motion-repository.service.ts | 15 +- .../statute-paragraph-repository.service.ts | 17 +-- .../{ => tag-list}/tag-list.component.css | 0 .../{ => tag-list}/tag-list.component.html | 0 .../{ => tag-list}/tag-list.component.spec.ts | 2 +- .../{ => tag-list}/tag-list.component.ts | 48 +++--- .../tags/services/tag-repository.service.ts | 15 +- .../src/app/site/tags/tag-routing.module.ts | 2 +- client/src/app/site/tags/tag.module.ts | 2 +- .../group-list/group-list.component.ts | 39 +++-- .../user-detail/user-detail.component.ts | 31 ++-- .../services/group-repository.service.ts | 15 +- .../users/services/user-repository.service.ts | 15 +- 33 files changed, 329 insertions(+), 400 deletions(-) rename client/src/app/site/tags/components/{ => tag-list}/tag-list.component.css (100%) rename client/src/app/site/tags/components/{ => tag-list}/tag-list.component.html (100%) rename client/src/app/site/tags/components/{ => tag-list}/tag-list.component.spec.ts (91%) rename client/src/app/site/tags/components/{ => tag-list}/tag-list.component.ts (71%) diff --git a/client/src/app/core/pruning-loader.ts b/client/src/app/core/pruning-loader.ts index 412a9d009..6c6ab4e61 100644 --- a/client/src/app/core/pruning-loader.ts +++ b/client/src/app/core/pruning-loader.ts @@ -1,6 +1,7 @@ import { TranslateLoader } from '@ngx-translate/core'; import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators/'; +import { Observable } from 'rxjs'; /** * 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. * @param lang language string (en, fr, de, ...) */ - public getTranslation(lang: string): any { + public getTranslation(lang: string): Observable { return this.http.get(`${this.prefix}${lang}${this.suffix}`).pipe(map((res: Object) => this.process(res))); } diff --git a/client/src/app/core/services/data-send.service.ts b/client/src/app/core/services/data-send.service.ts index bc5f15593..cca8da869 100644 --- a/client/src/app/core/services/data-send.service.ts +++ b/client/src/app/core/services/data-send.service.ts @@ -1,11 +1,10 @@ import { Injectable } from '@angular/core'; import { BaseModel } from '../../shared/models/base/base-model'; -import { Observable } from 'rxjs'; 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 */ @@ -16,38 +15,47 @@ export class DataSendService { /** * Construct a DataSendService * - * @param httpService The HTTP Client + * @param httpService The HTTP Service */ public constructor(private httpService: HttpService) {} /** - * Sends a post request with the model to the server. - * Usually for new Models + * Sends a post request with the model to the server to create it. + * + * @param model The model to create. */ - public createModel(model: BaseModel): Observable { + public async createModel(model: BaseModel): Promise { const restPath = `rest/${model.collectionString}/`; - return this.httpService.create(restPath, model) as Observable; + return await this.httpService.post(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 method the required http method. might be put or patch + * @param model The model that is meant to be changed. */ - public updateModel(model: BaseModel, method: HTTPMethod): Observable { - const restPath = `rest/${model.collectionString}/${model.id}`; - return this.httpService.update(restPath, model, method) as Observable; + public async updateModel(model: BaseModel): Promise { + const restPath = `rest/${model.collectionString}/${model.id}/`; + 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 - * @return Observable of BaseModel + * @param model The model to partially update. */ - public deleteModel(model: BaseModel): Observable { - const restPath = `rest/${model.collectionString}/${model.id}`; - return this.httpService.delete(restPath) as Observable; + public async partialUpdateModel(model: BaseModel): Promise { + const restPath = `rest/${model.collectionString}/${model.id}/`; + 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 { + const restPath = `rest/${model.collectionString}/${model.id}/`; + await this.httpService.delete(restPath); } } diff --git a/client/src/app/core/services/http.service.ts b/client/src/app/core/services/http.service.ts index b0e40bdee..3dfed62de 100644 --- a/client/src/app/core/services/http.service.ts +++ b/client/src/app/core/services/http.service.ts @@ -1,105 +1,92 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; /** * Enum for different HTTPMethods */ export enum HTTPMethod { - PUT, - PATCH + GET = 'get', + 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({ providedIn: 'root' }) -/** - * Service for sending data back to server - */ + export class HttpService { /** - * Construct a DataSendService + * Construct a HttpService * * @param http The HTTP Client */ public constructor(private http: HttpClient) {} - /** - * Exectures a post on a url with a certain object - * @param url string of the url to send semothing to - * @param obj the object that should be send - */ - public create(url: string, obj: object): Observable { - url = this.formatForSlash(url); - return this.http.post(url, obj).pipe( - tap( - response => { - // TODO: Message, Notify, Etc - console.log('New object added. Response :\n ', response); - }, - error => console.error('Error:\n ', error) - ) - ); - } + private async send(url: string, method: HTTPMethod, data?: any): Promise { + if (!url.endsWith('/')) { + url += '/'; + } - /** - * Adds a / at the end, if there is none - * @param str the string where the / should be checked - */ - private formatForSlash(str: string): string { - let retStr = ''; - retStr += str; - return retStr.endsWith('/') ? retStr : (retStr += '/'); - } + const options = { + body: data, + }; - /** - * Save object in the server - * - * @param url string of the url to send semothing to - * @param obj 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 { - url = this.formatForSlash(url); - if (method === null || method === HTTPMethod.PATCH) { - return this.http.patch(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(url, obj).pipe( - tap( - response => { - console.log('Update object. Response :\n ', response); - }, - error => console.error('Error :\n', error) - ) - ); + try { + const response = await this.http.request(method, url, options).toPromise(); + return response; + } catch (e) { + console.log("error", e); + throw e; } } /** - * Deletes the given object on the server - * - * @param url the url that should be called to delete the object - * @return Observable of object + * 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 delete(url: string): Observable { - url = this.formatForSlash(url); - return this.http.delete(url).pipe( - tap( - response => { - // TODO: Message, Notify, Etc - console.log('Delete object. Response:\n', response); - }, - error => console.error('Error: \n', error) - ) - ); + public async get(url: string, data?: any): Promise { + return await this.send(url, HTTPMethod.GET, data); + } + + /** + * Exectures a post on a url with a certain object + * @param url string of the url to send semothing to + * @param data The data to send + */ + public async post(url: string, data: any): Promise { + return await this.send(url, HTTPMethod.POST, data); + } + + /** + * Exectures a put on a url with a certain object + * @param url string of the url to send semothing to + * @param data the object that should be send + */ + public async patch(url: string, data: any): Promise { + return await this.send(url, HTTPMethod.PATCH, data); + } + + /** + * Exectures a put on a url with a certain object + * @param url the url that should be called + * @param data: The data to send + */ + public async put(url: string, data: any): Promise { + return await this.send(url, HTTPMethod.PUT, data); + } + + /** + * Makes a delete request. + * @param url the url that should be called + * @param data An optional data to send in the requestbody. + */ + public async delete(url: string, data?: any): Promise { + return await this.send(url, HTTPMethod.DELETE, data); } } diff --git a/client/src/app/shared/components/legal-notice-content/legal-notice-content.component.ts b/client/src/app/shared/components/legal-notice-content/legal-notice-content.component.ts index 39e0cd738..4632640fb 100644 --- a/client/src/app/shared/components/legal-notice-content/legal-notice-content.component.ts +++ b/client/src/app/shared/components/legal-notice-content/legal-notice-content.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { LoginDataService } from '../../../core/services/login-data.service'; 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 @@ -83,7 +83,7 @@ export class LegalNoticeContentComponent implements OnInit { public constructor( private loginDataService: LoginDataService, private translate: TranslateService, - private http: HttpClient + private http: HttpService ) {} /** @@ -97,10 +97,13 @@ export class LegalNoticeContentComponent implements OnInit { }); // Query the version info. - this.http - .get(environment.urlPrefix + '/core/version/', {}) - .subscribe((info: VersionResponse) => { + this.http.get(environment.urlPrefix + '/core/version/', {}).then( + info => { this.versionInfo = info; - }); + }, + () => { + // TODO: error handling if the version info could not be loaded + } + ); } } diff --git a/client/src/app/site/agenda/services/agenda-repository.service.ts b/client/src/app/site/agenda/services/agenda-repository.service.ts index fb01cfd70..7cb6029dc 100644 --- a/client/src/app/site/agenda/services/agenda-repository.service.ts +++ b/client/src/app/site/agenda/services/agenda-repository.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; import { BaseRepository } from '../../base/base-repository'; 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 { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model'; import { BaseModel } from '../../../shared/models/base/base-model'; +import { Identifiable } from '../../../shared/models/base/identifiable'; /** * Repository service for users @@ -49,7 +49,7 @@ export class AgendaRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public update(item: Partial, viewUser: ViewItem): Observable { + public async update(item: Partial, viewUser: ViewItem): Promise { return null; } @@ -58,7 +58,7 @@ export class AgendaRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public delete(item: ViewItem): Observable { + public async delete(item: ViewItem): Promise { return null; } @@ -67,7 +67,7 @@ export class AgendaRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public create(item: Item): Observable { + public async create(item: Item): Promise { return null; } diff --git a/client/src/app/site/assignments/services/assignment-repository.service.ts b/client/src/app/site/assignments/services/assignment-repository.service.ts index 98a7ffb16..54b1c3c3d 100644 --- a/client/src/app/site/assignments/services/assignment-repository.service.ts +++ b/client/src/app/site/assignments/services/assignment-repository.service.ts @@ -4,9 +4,9 @@ import { Assignment } from '../../../shared/models/assignments/assignment'; import { User } from '../../../shared/models/users/user'; import { Tag } from '../../../shared/models/core/tag'; import { Item } from '../../../shared/models/agenda/item'; -import { Observable } from 'rxjs'; import { BaseRepository } from '../../base/base-repository'; import { DataStoreService } from '../../../core/services/data-store.service'; +import { Identifiable } from '../../../shared/models/base/identifiable'; /** * Repository Service for Assignments. @@ -25,15 +25,15 @@ export class AssignmentRepositoryService extends BaseRepository, viewAssignment: ViewAssignment): Observable { + public async update(assignment: Partial, viewAssignment: ViewAssignment): Promise { return null; } - public delete(viewAssignment: ViewAssignment): Observable { + public async delete(viewAssignment: ViewAssignment): Promise { return null; } - public create(assignment: Assignment): Observable { + public async create(assignment: Assignment): Promise { return null; } diff --git a/client/src/app/site/base/base-repository.ts b/client/src/app/site/base/base-repository.ts index 5120f4fe1..c98d9ba57 100644 --- a/client/src/app/site/base/base-repository.ts +++ b/client/src/app/site/base/base-repository.ts @@ -4,6 +4,7 @@ import { BaseViewModel } from './base-view-model'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model'; import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service'; import { DataStoreService } from '../../core/services/data-store.service'; +import { Identifiable } from '../../shared/models/base/identifiable'; export abstract class BaseRepository extends OpenSlidesComponent { /** @@ -78,14 +79,14 @@ export abstract class BaseRepository, viewModel: V): Observable; + public abstract async update(update: Partial, viewModel: V): Promise; /** * Deletes a given Model * @param update the update that should be created * @param viewModel the view model that the update is based on */ - public abstract delete(viewModel: V): Observable; + public abstract async delete(viewModel: V): Promise; /** * Creates a new model @@ -93,7 +94,7 @@ export abstract class BaseRepository; + public abstract async create(update: M): Promise; /** * Creates a view model out of a base model. diff --git a/client/src/app/site/config/components/config-field/config-field.component.ts b/client/src/app/site/config/components/config-field/config-field.component.ts index 964b8f471..7474c61e8 100644 --- a/client/src/app/site/config/components/config-field/config-field.component.ts +++ b/client/src/app/site/config/components/config-field/config-field.component.ts @@ -5,7 +5,6 @@ import { ViewConfig } from '../../models/view-config'; import { BaseComponent } from '../../../../base.component'; import { FormGroup, FormBuilder } from '@angular/forms'; import { ConfigRepositoryService } from '../../services/config-repository.service'; -import { tap } from 'rxjs/operators'; import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher'; /** @@ -117,26 +116,19 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit { /** * Updates the this config field. */ - private update(value: any): void { + private async update(value: any): Promise { // TODO: Fix the Datetimepicker parser and formatter. if (this.configItem.inputType === 'datetimepicker') { value = Date.parse(value); } this.debounceTimeout = null; - this.repo - .update({ value: value }, this.configItem) - .pipe( - tap( - response => { - this.error = null; - this.showSuccessIcon(); - }, - error => { - this.setError(error.error.detail); - } - ) - ) - .subscribe(); + try { + await this.repo.update({ value: value }, this.configItem); + this.error = null; + this.showSuccessIcon(); + } catch (e) { + this.setError(e.error.detail); + } } /** diff --git a/client/src/app/site/config/services/config-repository.service.ts b/client/src/app/site/config/services/config-repository.service.ts index 4c2906e37..afdde0a24 100644 --- a/client/src/app/site/config/services/config-repository.service.ts +++ b/client/src/app/site/config/services/config-repository.service.ts @@ -6,7 +6,8 @@ import { Config } from '../../../shared/models/core/config'; import { Observable, BehaviorSubject } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.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. @@ -85,7 +86,7 @@ export class ConfigRepositoryService extends BaseRepository /** * 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); this.constantsService.get('OpenSlidesConfigVariables').subscribe(constant => { @@ -180,12 +181,12 @@ export class ConfigRepositoryService extends BaseRepository /** * Saves a config value. */ - public update(config: Partial, viewConfig: ViewConfig): Observable { + public async update(config: Partial, viewConfig: ViewConfig): Promise { const updatedConfig = new Config(); updatedConfig.patchValues(viewConfig.config); updatedConfig.patchValues(config); // TODO: Use datasendService, if it can switch correctly between put, post and patch - return this.http.put( + await this.http.put( 'rest/' + updatedConfig.collectionString + '/' + updatedConfig.key + '/', updatedConfig ); @@ -197,7 +198,7 @@ export class ConfigRepositoryService extends BaseRepository * * Function exists solely to correctly implement {@link BaseRepository} */ - public delete(config: ViewConfig): Observable { + public async delete(config: ViewConfig): Promise { throw new Error('Config variables cannot be deleted'); } @@ -207,7 +208,7 @@ export class ConfigRepositoryService extends BaseRepository * * Function exists solely to correctly implement {@link BaseRepository} */ - public create(config: Config): Observable { + public async create(config: Config): Promise { throw new Error('Config variables cannot be created'); } diff --git a/client/src/app/site/login/components/login-mask/login-mask.component.ts b/client/src/app/site/login/components/login-mask/login-mask.component.ts index d5d352cf1..d545c63d2 100644 --- a/client/src/app/site/login/components/login-mask/login-mask.component.ts +++ b/client/src/app/site/login/components/login-mask/login-mask.component.ts @@ -7,11 +7,12 @@ import { OperatorService } from 'app/core/services/operator.service'; import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material'; import { FormGroup, Validators, FormBuilder } from '@angular/forms'; 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 { OpenSlidesService } from '../../../../core/services/openslides.service'; import { LoginDataService } from '../../../../core/services/login-data.service'; import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher'; +import { HttpService } from '../../../../core/services/http.service'; /** * Login mask component. @@ -72,7 +73,7 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr private operator: OperatorService, private router: Router, private formBuilder: FormBuilder, - private http: HttpClient, + private http: HttpService, private matSnackBar: MatSnackBar, private OpenSlides: OpenSlidesService, private loginDataService: LoginDataService @@ -89,15 +90,20 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr */ public ngOnInit(): void { // Get the login data. Save information to the login data service - this.http.get(environment.urlPrefix + '/users/login/', {}).subscribe(response => { - if (response.info_text) { - this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), { - duration: 5000 - }); + this.http.get(environment.urlPrefix + '/users/login/').then( + response => { + if (response.info_text) { + this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), { + duration: 5000 + }); + } + this.loginDataService.setPrivacyPolicy(response.privacy_policy); + this.loginDataService.setLegalNotice(response.legal_notice); + }, + () => { + // TODO: Error handling } - this.loginDataService.setPrivacyPolicy(response.privacy_policy); - this.loginDataService.setLegalNotice(response.legal_notice); - }); + ); } public ngOnDestroy(): void { diff --git a/client/src/app/site/mediafiles/services/mediafile-repository.service.ts b/client/src/app/site/mediafiles/services/mediafile-repository.service.ts index c4a03adee..0b48b564e 100644 --- a/client/src/app/site/mediafiles/services/mediafile-repository.service.ts +++ b/client/src/app/site/mediafiles/services/mediafile-repository.service.ts @@ -4,8 +4,8 @@ import { BaseRepository } from '../../base/base-repository'; import { ViewMediafile } from '../models/view-mediafile'; import { Mediafile } from '../../../shared/models/mediafiles/mediafile'; import { User } from '../../../shared/models/users/user'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.service'; +import { Identifiable } from '../../../shared/models/base/identifiable'; /** * Repository for files @@ -27,7 +27,7 @@ export class MediafileRepositoryService extends BaseRepository, viewFile: ViewMediafile): Observable { + public async update(file: Partial, viewFile: ViewMediafile): Promise { return null; } @@ -36,7 +36,7 @@ export class MediafileRepositoryService extends BaseRepository { + public async delete(file: ViewMediafile): Promise { return null; } @@ -45,7 +45,7 @@ export class MediafileRepositoryService extends BaseRepository { + public async create(file: Mediafile): Promise { return null; } diff --git a/client/src/app/site/motions/components/category-list/category-list.component.ts b/client/src/app/site/motions/components/category-list/category-list.component.ts index 6d86e4dda..c278995a2 100644 --- a/client/src/app/site/motions/components/category-list/category-list.component.ts +++ b/client/src/app/site/motions/components/category-list/category-list.component.ts @@ -10,8 +10,6 @@ import { ViewCategory } from '../../models/view-category'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { Motion } from '../../../../shared/models/motions/motion'; 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'; /** @@ -66,7 +64,6 @@ export class CategoryListComponent extends BaseComponent implements OnInit { protected translate: TranslateService, private repo: CategoryRepositoryService, private formBuilder: FormBuilder, - private motionRepo: MotionRepositoryService, private promptService: PromptService ) { super(titleService, translate); @@ -122,12 +119,11 @@ export class CategoryListComponent extends BaseComponent implements OnInit { /** * Creates a new category. Executed after hitting save. */ - public onCreateButton(): void { + public async onCreateButton(): Promise { if (this.createForm.valid) { this.categoryToCreate.patchValues(this.createForm.value as Category); - this.repo.create(this.categoryToCreate).subscribe(resp => { - this.categoryToCreate = null; - }); + await this.repo.create(this.categoryToCreate) + this.categoryToCreate = null; } } @@ -147,18 +143,17 @@ export class CategoryListComponent extends BaseComponent implements OnInit { /** * Saves the categories */ - public onSaveButton(viewCategory: ViewCategory): void { + public async onSaveButton(viewCategory: ViewCategory): Promise { if (this.updateForm.valid) { - this.repo.update(this.updateForm.value as Partial, viewCategory).subscribe(resp => { - this.onCancelButton(); - this.sortDataSource(); - }); + await this.repo.update(this.updateForm.value as Partial, viewCategory); + this.onCancelButton(); + this.sortDataSource(); } // get the sorted motions if (this.sortSelector) { 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 */ - public async onDeleteButton(viewCategory: ViewCategory): Promise { + public async onDeleteButton(viewCategory: ViewCategory): Promise { const content = this.translate.instant('Delete') + ` ${viewCategory.name}?`; if (await this.promptService.open('Are you sure?', content)) { - const motList = this.motionsInCategory(viewCategory.category); - motList.forEach(motion => { - motion.category_id = null; - this.motionRepo.update(motion, new ViewMotion(motion)); - }); - - this.repo.delete(viewCategory).subscribe(resp => { - this.onCancelButton(); - }); + await this.repo.delete(viewCategory); + this.onCancelButton(); } } diff --git a/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.ts b/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.ts index 2d737d2bb..46221c19f 100644 --- a/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.ts +++ b/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.ts @@ -109,7 +109,7 @@ export class MotionChangeRecommendationComponent { }); } - public saveChangeRecommendation(): void { + public async saveChangeRecommendation(): Promise { this.changeReco.updateChangeReco( this.contentForm.controls.diffType.value, this.contentForm.controls.text.value, @@ -117,21 +117,13 @@ export class MotionChangeRecommendationComponent { ); if (this.newReco) { - this.repo.createByViewModel(this.changeReco).subscribe(response => { - if (response.id) { - this.dialogRef.close(response); - } else { - // @TODO Show an error message - } - }); + await this.repo.createByViewModel(this.changeReco); + this.dialogRef.close(); + // @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 - } - }); + await this.repo.update(this.changeReco.changeRecommendation, this.changeReco); + this.dialogRef.close(); + // @TODO Show an error message } } } diff --git a/client/src/app/site/motions/components/motion-comment-section-list/motion-comment-section-list.component.ts b/client/src/app/site/motions/components/motion-comment-section-list/motion-comment-section-list.component.ts index b1b118bd6..48c5b7d17 100644 --- a/client/src/app/site/motions/components/motion-comment-section-list/motion-comment-section-list.component.ts +++ b/client/src/app/site/motions/components/motion-comment-section-list/motion-comment-section-list.component.ts @@ -111,12 +111,11 @@ export class MotionCommentSectionListComponent extends BaseComponent implements } } - public create(): void { + public async create(): Promise { if (this.createForm.valid) { this.commentSectionToCreate.patchValues(this.createForm.value as MotionCommentSection); - this.repo.create(this.commentSectionToCreate).subscribe(resp => { - this.commentSectionToCreate = null; - }); + await this.repo.create(this.commentSectionToCreate); + this.commentSectionToCreate = null; } } @@ -137,23 +136,21 @@ export class MotionCommentSectionListComponent extends BaseComponent implements /** * Saves the categories */ - public onSaveButton(viewSection: ViewMotionCommentSection): void { + public async onSaveButton(viewSection: ViewMotionCommentSection): Promise { if (this.updateForm.valid) { - this.repo.update(this.updateForm.value as Partial, viewSection).subscribe(resp => { - this.openId = this.editId = null; - }); + await this.repo.update(this.updateForm.value as Partial, viewSection); + this.openId = this.editId = null; } } /** * is executed, when the delete button is pressed */ - public async onDeleteButton(viewSection: ViewMotionCommentSection): Promise { + public async onDeleteButton(viewSection: ViewMotionCommentSection): Promise { const content = this.translate.instant('Delete') + ` ${viewSection.name}?`; if (await this.promptService.open('Are you sure?', content)) { - this.repo.delete(viewSection).subscribe(resp => { - this.openId = this.editId = null; - }); + await this.repo.delete(viewSection); + this.openId = this.editId = null; } } diff --git a/client/src/app/site/motions/components/motion-detail-diff/motion-detail-diff.component.ts b/client/src/app/site/motions/components/motion-detail-diff/motion-detail-diff.component.ts index e83730222..cc4cde7da 100644 --- a/client/src/app/site/motions/components/motion-detail-diff/motion-detail-diff.component.ts +++ b/client/src/app/site/motions/components/motion-detail-diff/motion-detail-diff.component.ts @@ -170,12 +170,12 @@ export class MotionDetailDiffComponent implements AfterViewInit { * @param {ViewChangeReco} change * @param {string} value */ - public setAcceptanceValue(change: ViewChangeReco, value: string): void { + public async setAcceptanceValue(change: ViewChangeReco, value: string): Promise { if (value === 'accepted') { - this.recoRepo.setAccepted(change).subscribe(); // Subscribe to trigger HTTP request + await this.recoRepo.setAccepted(change); } 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 {boolean} internal */ - public setInternal(change: ViewChangeReco, internal: boolean): void { - this.recoRepo.setInternal(change, internal).subscribe(); // Subscribe to trigger HTTP request + public async setInternal(change: ViewChangeReco, internal: boolean): Promise { + await this.recoRepo.setInternal(change, internal); } /** @@ -196,10 +196,10 @@ export class MotionDetailDiffComponent implements AfterViewInit { * @param {ViewChangeReco} reco * @param {MouseEvent} $event */ - public deleteChangeRecommendation(reco: ViewChangeReco, $event: MouseEvent): void { - this.recoRepo.delete(reco).subscribe(); // Subscribe to trigger HTTP request + public async deleteChangeRecommendation(reco: ViewChangeReco, $event: MouseEvent): Promise { $event.stopPropagation(); $event.preventDefault(); + await this.recoRepo.delete(reco); } /** diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts index a8c4c0e5c..6fcd7a2a3 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts @@ -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. */ - public saveMotion(): void { + public async saveMotion(): Promise { const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value }; const fromForm = new Motion(); fromForm.deserialize(newMotionValues); if (this.newMotion) { - this.repo.create(fromForm).subscribe(response => { - if (response.id) { - this.router.navigate(['./motions/' + response.id]); - } - }); + const response = await this.repo.create(fromForm); + this.router.navigate(['./motions/' + response.id]); } else { - this.repo.update(fromForm, this.motionCopy).subscribe(response => { - // if the motion was successfully updated, change the edit mode. - // TODO: Show errors if there appear here - if (response.id) { - this.editMotion = false; - } - }); - - // 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 - ); - } - } + await this.repo.update(fromForm, this.motionCopy); + // if the motion was successfully updated, change the edit mode. + this.editMotion = false; + // TODO: Show errors if there appear here } } @@ -329,7 +309,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { * TODO: Repo should handle */ public deleteMotionButton(): void { - this.repo.delete(this.motion).subscribe(answer => { + this.repo.delete(this.motion).then(() => { this.router.navigate(['./motions/']); }); const motList = this.categoryRepo.getMotionsOfCategory(this.motion.category); diff --git a/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.ts b/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.ts index d70ec6801..fae5740bc 100644 --- a/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.ts +++ b/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.ts @@ -85,12 +85,11 @@ export class StatuteParagraphListComponent extends BaseComponent implements OnIn } } - public create(): void { + public async create(): Promise { if (this.createForm.valid) { this.statuteParagraphToCreate.patchValues(this.createForm.value as StatuteParagraph); - this.repo.create(this.statuteParagraphToCreate).subscribe(resp => { - this.statuteParagraphToCreate = null; - }); + await this.repo.create(this.statuteParagraphToCreate); + this.statuteParagraphToCreate = null; } } @@ -110,25 +109,21 @@ export class StatuteParagraphListComponent extends BaseComponent implements OnIn /** * Saves the statute paragrpah */ - public onSaveButton(viewStatuteParagraph: ViewStatuteParagraph): void { + public async onSaveButton(viewStatuteParagraph: ViewStatuteParagraph): Promise { if (this.updateForm.valid) { - this.repo - .update(this.updateForm.value as Partial, viewStatuteParagraph) - .subscribe(resp => { - this.openId = this.editId = null; - }); + await this.repo.update(this.updateForm.value as Partial, viewStatuteParagraph); + this.openId = this.editId = null; } } /** * is executed, when the delete button is pressed */ - public async onDeleteButton(viewStatuteParagraph: ViewStatuteParagraph): Promise { + public async onDeleteButton(viewStatuteParagraph: ViewStatuteParagraph): Promise { const content = this.translate.instant('Delete') + ` ${viewStatuteParagraph.title}?`; if (await this.promptService.open('Are you sure?', content)) { - this.repo.delete(viewStatuteParagraph).subscribe(resp => { - this.openId = this.editId = null; - }); + await this.repo.delete(viewStatuteParagraph); + this.openId = this.editId = null; } } diff --git a/client/src/app/site/motions/services/category-repository.service.ts b/client/src/app/site/motions/services/category-repository.service.ts index 17406cd6e..48cbdf4a4 100644 --- a/client/src/app/site/motions/services/category-repository.service.ts +++ b/client/src/app/site/motions/services/category-repository.service.ts @@ -2,12 +2,12 @@ import { Injectable } from '@angular/core'; import { Category } from '../../../shared/models/motions/category'; import { ViewCategory } from '../models/view-category'; import { DataSendService } from '../../../core/services/data-send.service'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.service'; import { BaseRepository } from '../../base/base-repository'; import { Motion } from '../../../shared/models/motions/motion'; 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 @@ -41,11 +41,11 @@ export class CategoryRepositoryService extends BaseRepository { - return this.dataSend.createModel(newCategory); + public async create(newCategory: Category): Promise { + return await this.dataSend.createModel(newCategory); } - public update(category: Partial, viewCategory?: ViewCategory): Observable { + public async update(category: Partial, viewCategory: ViewCategory): Promise { let updateCategory: Category; if (viewCategory) { updateCategory = viewCategory.category; @@ -53,12 +53,12 @@ export class CategoryRepositoryService extends BaseRepository { + public async delete(viewCategory: ViewCategory): Promise { const category = viewCategory.category; - return this.dataSend.deleteModel(category); + await this.dataSend.deleteModel(category); } /** @@ -91,10 +91,10 @@ export class CategoryRepositoryService extends BaseRepository { + public async updateCategoryNumbering(category: Category, motionList: Motion[]): Promise { const categoryNumbering = new CategoryNumbering(); categoryNumbering.setMotions(motionList); - return this.sentCategoryNumbering(category, categoryNumbering); + await this.sentCategoryNumbering(category, categoryNumbering); } /** @@ -102,8 +102,8 @@ export class CategoryRepositoryService extends BaseRepository { + protected async sentCategoryNumbering(category: Category, categoryNumbering: CategoryNumbering): Promise { const collectionString = 'rest/motions/category/' + category.id + '/numbering/'; - return this.httpService.create(collectionString, categoryNumbering); + await this.httpService.post(collectionString, categoryNumbering); } } diff --git a/client/src/app/site/motions/services/change-recommendation-repository.service.ts b/client/src/app/site/motions/services/change-recommendation-repository.service.ts index f3fac313e..b34c26bb8 100644 --- a/client/src/app/site/motions/services/change-recommendation-repository.service.ts +++ b/client/src/app/site/motions/services/change-recommendation-repository.service.ts @@ -10,7 +10,7 @@ import { BaseRepository } from '../../base/base-repository'; import { DataStoreService } from '../../../core/services/data-store.service'; import { MotionChangeReco } from '../../../shared/models/motions/motion-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 @@ -44,8 +44,8 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { - return this.dataSend.createModel(changeReco) as Observable; + public async create(changeReco: MotionChangeReco): Promise { + return await this.dataSend.createModel(changeReco); } /** @@ -53,13 +53,13 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { - return this.create(view.changeRecommendation).pipe( - map((changeReco: MotionChangeReco) => { - return new ViewChangeReco(changeReco); - }) - ); + public async createByViewModel(view: ViewChangeReco): Promise { + return await this.dataSend.createModel(view.changeRecommendation); + // return new ViewChangeReco(cr); } /** @@ -78,8 +78,8 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { - return this.dataSend.deleteModel(viewModel.changeRecommendation) as Observable; + public async delete(viewModel: ViewChangeReco): Promise { + await this.dataSend.deleteModel(viewModel.changeRecommendation); } /** @@ -91,10 +91,10 @@ export class ChangeRecommendationRepositoryService extends BaseRepository} update the form data containing the update values * @param {ViewChangeReco} viewModel The View Change Recommendation. If not present, a new motion will be created */ - public update(update: Partial, viewModel: ViewChangeReco): Observable { + public async update(update: Partial, viewModel: ViewChangeReco): Promise { const changeReco = viewModel.changeRecommendation; changeReco.patchValues(update); - return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable; + await this.dataSend.partialUpdateModel(changeReco); } /** @@ -113,12 +113,12 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { + public async setAccepted(change: ViewChangeReco): Promise { const changeReco = change.changeRecommendation; changeReco.patchValues({ rejected: false }); - return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable; + await this.dataSend.partialUpdateModel(changeReco); } /** @@ -126,12 +126,12 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { + public async setRejected(change: ViewChangeReco): Promise { const changeReco = change.changeRecommendation; changeReco.patchValues({ rejected: true }); - return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable; + await this.dataSend.partialUpdateModel(changeReco); } /** @@ -140,11 +140,11 @@ export class ChangeRecommendationRepositoryService extends BaseRepository { + public async setInternal(change: ViewChangeReco, internal: boolean): Promise { const changeReco = change.changeRecommendation; changeReco.patchValues({ internal: internal }); - return this.dataSend.updateModel(changeReco, HTTPMethod.PATCH) as Observable; + await this.dataSend.partialUpdateModel(changeReco); } } diff --git a/client/src/app/site/motions/services/motion-comment-section-repository.service.ts b/client/src/app/site/motions/services/motion-comment-section-repository.service.ts index fb9e7d006..19edc8223 100644 --- a/client/src/app/site/motions/services/motion-comment-section-repository.service.ts +++ b/client/src/app/site/motions/services/motion-comment-section-repository.service.ts @@ -1,12 +1,11 @@ import { Injectable } from '@angular/core'; import { DataSendService } from '../../../core/services/data-send.service'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.service'; import { BaseRepository } from '../../base/base-repository'; import { ViewMotionCommentSection } from '../models/view-motion-comment-section'; import { MotionCommentSection } from '../../../shared/models/motions/motion-comment-section'; 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 @@ -41,11 +40,11 @@ export class MotionCommentSectionRepositoryService extends BaseRepository< return new ViewMotionCommentSection(section, read_groups, write_groups); } - public create(section: MotionCommentSection): Observable { - return this.dataSend.createModel(section); + public async create(section: MotionCommentSection): Promise { + return await this.dataSend.createModel(section); } - public update(section: Partial, viewSection?: ViewMotionCommentSection): Observable { + public async update(section: Partial, viewSection?: ViewMotionCommentSection): Promise { let updateSection: MotionCommentSection; if (viewSection) { updateSection = viewSection.section; @@ -53,10 +52,10 @@ export class MotionCommentSectionRepositoryService extends BaseRepository< updateSection = new MotionCommentSection(); } updateSection.patchValues(section); - return this.dataSend.updateModel(updateSection, HTTPMethod.PUT); + await this.dataSend.updateModel(updateSection); } - public delete(viewSection: ViewMotionCommentSection): Observable { - return this.dataSend.deleteModel(viewSection.section); + public async delete(viewSection: ViewMotionCommentSection): Promise { + await this.dataSend.deleteModel(viewSection.section); } } diff --git a/client/src/app/site/motions/services/motion-repository.service.ts b/client/src/app/site/motions/services/motion-repository.service.ts index 48efeb56e..d5ffa43cc 100644 --- a/client/src/app/site/motions/services/motion-repository.service.ts +++ b/client/src/app/site/motions/services/motion-repository.service.ts @@ -7,7 +7,6 @@ import { Category } from '../../../shared/models/motions/category'; import { Workflow } from '../../../shared/models/motions/workflow'; import { WorkflowState } from '../../../shared/models/motions/workflow-state'; import { ChangeRecoMode, ViewMotion } from '../models/view-motion'; -import { Observable } from 'rxjs'; import { BaseRepository } from '../../base/base-repository'; import { DataStoreService } from '../../../core/services/data-store.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 { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco'; 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) @@ -79,11 +78,11 @@ export class MotionRepositoryService extends BaseRepository * @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() */ - public create(motion: Motion): Observable { + public async create(motion: Motion): Promise { if (!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 * @param update the form data containing the update values * @param viewMotion The View Motion. If not present, a new motion will be created */ - public update(update: Partial, viewMotion: ViewMotion): Observable { + public async update(update: Partial, viewMotion: ViewMotion): Promise { const motion = viewMotion.motion; motion.patchValues(update); - return this.dataSend.updateModel(motion, HTTPMethod.PATCH); + await this.dataSend.partialUpdateModel(motion); } /** @@ -108,8 +107,8 @@ export class MotionRepositoryService extends BaseRepository * to {@link DataSendService} * @param viewMotion */ - public delete(viewMotion: ViewMotion): Observable { - return this.dataSend.deleteModel(viewMotion.motion); + public async delete(viewMotion: ViewMotion): Promise { + await this.dataSend.deleteModel(viewMotion.motion); } /** diff --git a/client/src/app/site/motions/services/statute-paragraph-repository.service.ts b/client/src/app/site/motions/services/statute-paragraph-repository.service.ts index 5d9227c52..8d959dfea 100644 --- a/client/src/app/site/motions/services/statute-paragraph-repository.service.ts +++ b/client/src/app/site/motions/services/statute-paragraph-repository.service.ts @@ -1,11 +1,10 @@ import { Injectable } from '@angular/core'; import { DataSendService } from '../../../core/services/data-send.service'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.service'; import { BaseRepository } from '../../base/base-repository'; import { ViewStatuteParagraph } from '../models/view-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 @@ -32,20 +31,20 @@ export class StatuteParagraphRepositoryService extends BaseRepository { - return this.dataSend.createModel(statuteParagraph); + public async create(statuteParagraph: StatuteParagraph): Promise { + return await this.dataSend.createModel(statuteParagraph); } - public update( + public async update( statuteParagraph: Partial, viewStatuteParagraph: ViewStatuteParagraph - ): Observable { + ): Promise { const updateParagraph = viewStatuteParagraph.statuteParagraph; updateParagraph.patchValues(statuteParagraph); - return this.dataSend.updateModel(updateParagraph, HTTPMethod.PUT); + await this.dataSend.updateModel(updateParagraph); } - public delete(viewStatuteParagraph: ViewStatuteParagraph): Observable { - return this.dataSend.deleteModel(viewStatuteParagraph.statuteParagraph); + public async delete(viewStatuteParagraph: ViewStatuteParagraph): Promise { + await this.dataSend.deleteModel(viewStatuteParagraph.statuteParagraph); } } diff --git a/client/src/app/site/tags/components/tag-list.component.css b/client/src/app/site/tags/components/tag-list/tag-list.component.css similarity index 100% rename from client/src/app/site/tags/components/tag-list.component.css rename to client/src/app/site/tags/components/tag-list/tag-list.component.css diff --git a/client/src/app/site/tags/components/tag-list.component.html b/client/src/app/site/tags/components/tag-list/tag-list.component.html similarity index 100% rename from client/src/app/site/tags/components/tag-list.component.html rename to client/src/app/site/tags/components/tag-list/tag-list.component.html diff --git a/client/src/app/site/tags/components/tag-list.component.spec.ts b/client/src/app/site/tags/components/tag-list/tag-list.component.spec.ts similarity index 91% rename from client/src/app/site/tags/components/tag-list.component.spec.ts rename to client/src/app/site/tags/components/tag-list/tag-list.component.spec.ts index 2a17b6e37..639e810e7 100644 --- a/client/src/app/site/tags/components/tag-list.component.spec.ts +++ b/client/src/app/site/tags/components/tag-list/tag-list.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TagListComponent } from './tag-list.component'; -import { E2EImportsModule } from '../../../../e2e-imports.module'; +import { E2EImportsModule } from 'e2e-imports.module'; describe('TagListComponent', () => { let component: TagListComponent; diff --git a/client/src/app/site/tags/components/tag-list.component.ts b/client/src/app/site/tags/components/tag-list/tag-list.component.ts similarity index 71% rename from client/src/app/site/tags/components/tag-list.component.ts rename to client/src/app/site/tags/components/tag-list/tag-list.component.ts index e857e4efe..a5d1d9903 100644 --- a/client/src/app/site/tags/components/tag-list.component.ts +++ b/client/src/app/site/tags/components/tag-list/tag-list.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Title } from '@angular/platform-browser'; -import { Tag } from '../../../shared/models/core/tag'; -import { ListViewBaseComponent } from '../../base/list-view-base'; -import { TagRepositoryService } from '../services/tag-repository.service'; -import { ViewTag } from '../models/view-tag'; +import { Tag } from '../../../../shared/models/core/tag'; +import { ListViewBaseComponent } from '../../../base/list-view-base'; +import { TagRepositoryService } from '../../services/tag-repository.service'; +import { ViewTag } from '../../models/view-tag'; 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 @@ -70,42 +70,36 @@ export class TagListComponent extends ListViewBaseComponent implements /** * Saves a newly created tag. */ - public submitNewTag(): void { - if (this.tagForm.value && this.tagForm.valid) { - this.repo.create(this.tagForm.value).subscribe(response => { - if (response) { - this.tagForm.reset(); - this.cancelEditing(); - } - }); + public async submitNewTag(): Promise { + if (!this.tagForm.value || !this.tagForm.valid) { + return; } + await this.repo.create(this.tagForm.value); + this.tagForm.reset(); + this.cancelEditing(); } /** * Saves an edited tag. */ - public submitEditedTag(): void { - if (this.tagForm.value && this.tagForm.valid) { - const updateData = new Tag({ name: this.tagForm.value.name }); - - this.repo.update(updateData, this.selectedTag).subscribe(response => { - if (response) { - this.cancelEditing(); - } - }); + public async submitEditedTag(): Promise { + if (!this.tagForm.value || !this.tagForm.valid) { + return; } + const updateData = new Tag({ name: this.tagForm.value.name }); + + await this.repo.update(updateData, this.selectedTag); + this.cancelEditing(); } /** * Deletes the selected Tag after a successful confirmation. - * @async */ - public async deleteSelectedTag(): Promise { + public async deleteSelectedTag(): Promise { const content = this.translate.instant('Delete') + ` ${this.selectedTag.name}?`; if (await this.promptService.open(this.translate.instant('Are you sure?'), content)) { - this.repo.delete(this.selectedTag).subscribe(response => { - this.cancelEditing(); - }); + await this.repo.delete(this.selectedTag); + this.cancelEditing(); } } diff --git a/client/src/app/site/tags/services/tag-repository.service.ts b/client/src/app/site/tags/services/tag-repository.service.ts index 5bc15c423..fba6ca744 100644 --- a/client/src/app/site/tags/services/tag-repository.service.ts +++ b/client/src/app/site/tags/services/tag-repository.service.ts @@ -2,10 +2,9 @@ import { Injectable } from '@angular/core'; import { Tag } from '../../../shared/models/core/tag'; import { ViewTag } from '../models/view-tag'; import { DataSendService } from '../../../core/services/data-send.service'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.service'; 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 @@ -35,20 +34,20 @@ export class TagRepositoryService extends BaseRepository { return new ViewTag(tag); } - public create(update: Tag): Observable { + public async create(update: Tag): Promise { const newTag = new Tag(); newTag.patchValues(update); - return this.dataSend.createModel(newTag); + return await this.dataSend.createModel(newTag); } - public update(update: Partial, viewTag: ViewTag): Observable { + public async update(update: Partial, viewTag: ViewTag): Promise { const updateTag = new Tag(); updateTag.patchValues(viewTag.tag); updateTag.patchValues(update); - return this.dataSend.updateModel(updateTag, HTTPMethod.PUT); + await this.dataSend.updateModel(updateTag); } - public delete(viewTag: ViewTag): Observable { - return this.dataSend.deleteModel(viewTag.tag); + public async delete(viewTag: ViewTag): Promise { + await this.dataSend.deleteModel(viewTag.tag); } } diff --git a/client/src/app/site/tags/tag-routing.module.ts b/client/src/app/site/tags/tag-routing.module.ts index 28d767198..c2043794d 100644 --- a/client/src/app/site/tags/tag-routing.module.ts +++ b/client/src/app/site/tags/tag-routing.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; 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 }]; diff --git a/client/src/app/site/tags/tag.module.ts b/client/src/app/site/tags/tag.module.ts index 24d8ffed5..a87ed173a 100644 --- a/client/src/app/site/tags/tag.module.ts +++ b/client/src/app/site/tags/tag.module.ts @@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common'; import { TagRoutingModule } from './tag-routing.module'; import { SharedModule } from '../../shared/shared.module'; -import { TagListComponent } from './components/tag-list.component'; +import { TagListComponent } from './components/tag-list/tag-list.component'; @NgModule({ imports: [CommonModule, TagRoutingModule, SharedModule], diff --git a/client/src/app/site/users/components/group-list/group-list.component.ts b/client/src/app/site/users/components/group-list/group-list.component.ts index 8020f6a79..c307797c2 100644 --- a/client/src/app/site/users/components/group-list/group-list.component.ts +++ b/client/src/app/site/users/components/group-list/group-list.component.ts @@ -88,38 +88,35 @@ export class GroupListComponent extends BaseComponent implements OnInit { * Saves a newly created group. * @param form form data given by the group */ - public submitNewGroup(): void { - if (this.groupForm.value && this.groupForm.valid) { - this.repo.create(this.groupForm.value).subscribe(response => { - if (response) { - this.groupForm.reset(); - this.cancelEditing(); - } - }); + public async submitNewGroup(): Promise { + if (!this.groupForm.value || !this.groupForm.valid) { + return; } + await this.repo.create(this.groupForm.value); + this.groupForm.reset(); + this.cancelEditing(); } /** * Saves an edited group. * @param form form data given by the group */ - public submitEditedGroup(): void { - if (this.groupForm.value && this.groupForm.valid) { - const updateData = new Group({ name: this.groupForm.value.name }); - - this.repo.update(updateData, this.selectedGroup).subscribe(response => { - if (response) { - this.cancelEditing(); - } - }); + public async submitEditedGroup(): Promise { + if (!this.groupForm.value || !this.groupForm.valid) { + return; } + const updateData = new Group({ name: this.groupForm.value.name }); + + await this.repo.update(updateData, this.selectedGroup); + this.cancelEditing(); } /** * Deletes the selected Group */ - public deleteSelectedGroup(): void { - this.repo.delete(this.selectedGroup).subscribe(response => this.cancelEditing()); + public async deleteSelectedGroup(): Promise { + await this.repo.delete(this.selectedGroup) + this.cancelEditing(); } /** @@ -136,9 +133,9 @@ export class GroupListComponent extends BaseComponent implements OnInit { * @param group * @param perm */ - public togglePerm(viewGroup: ViewGroup, perm: string): void { + public async togglePerm(viewGroup: ViewGroup, perm: string): Promise { const updateData = new Group({ permissions: viewGroup.getAlteredPermissions(perm) }); - this.repo.update(updateData, viewGroup).subscribe(); + await this.repo.update(updateData, viewGroup); } /** diff --git a/client/src/app/site/users/components/user-detail/user-detail.component.ts b/client/src/app/site/users/components/user-detail/user-detail.component.ts index 117f4925c..d63975a20 100644 --- a/client/src/app/site/users/components/user-detail/user-detail.component.ts +++ b/client/src/app/site/users/components/user-detail/user-detail.component.ts @@ -253,23 +253,17 @@ export class UserDetailComponent implements OnInit { /** * Save / Submit a user */ - public saveUser(): void { + public async saveUser(): Promise { if (this.newUser) { - this.repo.create(this.personalInfoForm.value).subscribe( - response => { - this.newUser = false; - this.router.navigate([`./users/${response.id}`]); - }, - error => console.error('Creation of the user failed: ', error.error) - ); + const response = await this.repo.create(this.personalInfoForm.value); + this.newUser = false; + this.router.navigate([`./users/${response.id}`]); } else { - this.repo.update(this.personalInfoForm.value, this.user).subscribe( - response => { - this.setEditMode(false); - this.loadViewUser(response.id); - }, - error => console.error('Update of the user failed: ', error.error) - ); + // TODO (Issue #3962): We need a waiting-State, so if autoupdates come before the response, + // the user is also updated. + await this.repo.update(this.personalInfoForm.value, this.user); + this.setEditMode(false); + this.loadViewUser(this.user.id); } } @@ -290,10 +284,9 @@ export class UserDetailComponent implements OnInit { /** * click on the delete user button */ - public deleteUserButton(): void { - this.repo.delete(this.user).subscribe(response => { - this.router.navigate(['./users/']); - }); + public async deleteUserButton(): Promise { + await this.repo.delete(this.user); + this.router.navigate(['./users/']); } /** diff --git a/client/src/app/site/users/services/group-repository.service.ts b/client/src/app/site/users/services/group-repository.service.ts index 91e253579..a3c3c91a2 100644 --- a/client/src/app/site/users/services/group-repository.service.ts +++ b/client/src/app/site/users/services/group-repository.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; import { ViewGroup } from '../models/view-group'; 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 { DataSendService } from '../../../core/services/data-send.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 @@ -109,10 +108,10 @@ export class GroupRepositoryService extends BaseRepository { * * @param groupData form value. Usually not yet a real user */ - public create(groupData: Partial): Observable { + public async create(groupData: Partial): Promise { const newGroup = new Group(); newGroup.patchValues(groupData); - return this.dataSend.createModel(newGroup); + return await this.dataSend.createModel(newGroup); } /** @@ -121,18 +120,18 @@ export class GroupRepositoryService extends BaseRepository { * @param permission the new permission * @param viewGroup the selected Group */ - public update(groupData: Partial, viewGroup: ViewGroup): Observable { + public async update(groupData: Partial, viewGroup: ViewGroup): Promise { const updateGroup = new Group(); updateGroup.patchValues(viewGroup.group); updateGroup.patchValues(groupData); - return this.dataSend.updateModel(updateGroup, HTTPMethod.PUT); + await this.dataSend.updateModel(updateGroup); } /** * Deletes a given group */ - public delete(viewGroup: ViewGroup): Observable { - return this.dataSend.deleteModel(viewGroup.group); + public async delete(viewGroup: ViewGroup): Promise { + await this.dataSend.deleteModel(viewGroup.group); } public createViewModel(group: Group): ViewGroup { diff --git a/client/src/app/site/users/services/user-repository.service.ts b/client/src/app/site/users/services/user-repository.service.ts index 4c6b64b52..401d92163 100644 --- a/client/src/app/site/users/services/user-repository.service.ts +++ b/client/src/app/site/users/services/user-repository.service.ts @@ -4,10 +4,9 @@ import { BaseRepository } from '../../base/base-repository'; import { ViewUser } from '../models/view-user'; import { User } from '../../../shared/models/users/user'; import { Group } from '../../../shared/models/users/group'; -import { Observable } from 'rxjs'; import { DataStoreService } from '../../../core/services/data-store.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 @@ -31,7 +30,7 @@ export class UserRepositoryService extends BaseRepository { * @param update the forms values * @param viewUser */ - public update(update: Partial, viewUser: ViewUser): Observable { + public async update(update: Partial, viewUser: ViewUser): Promise { const updateUser = new User(); // copy the ViewUser to avoid manipulation of parameters updateUser.patchValues(viewUser.user); @@ -43,14 +42,14 @@ export class UserRepositoryService extends BaseRepository { updateUser.username = viewUser.username; } - return this.dataSend.updateModel(updateUser, HTTPMethod.PUT); + await this.dataSend.updateModel(updateUser); } /** * Deletes a given user */ - public delete(viewUser: ViewUser): Observable { - return this.dataSend.deleteModel(viewUser.user); + public async delete(viewUser: ViewUser): Promise { + await this.dataSend.deleteModel(viewUser.user); } /** @@ -59,7 +58,7 @@ export class UserRepositoryService extends BaseRepository { * TODO: used over not-yet-existing detail view * @param userData blank form value. Usually not yet a real user */ - public create(userData: Partial): Observable { + public async create(userData: Partial): Promise { const newUser = new User(); // collectionString of userData is still empty newUser.patchValues(userData); @@ -73,7 +72,7 @@ export class UserRepositoryService extends BaseRepository { } }); - return this.dataSend.createModel(newUser); + return await this.dataSend.createModel(newUser); } public createViewModel(user: User): ViewUser {