From 0feed4da6155588eee106b9d673afa01f61b8611 Mon Sep 17 00:00:00 2001 From: vktrrdk Date: Thu, 20 Apr 2023 17:19:46 +0200 Subject: [PATCH 1/4] fix(Project Overview): Prevent of sending bad request for unapproved projects --- src/app/api-connector/group.service.ts | 2 + .../application.model/application.model.ts | 6 ++- .../projectmanagement/overview.component.ts | 54 ++++++++++--------- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/app/api-connector/group.service.ts b/src/app/api-connector/group.service.ts index 81c34a6c35..860e12fe6d 100644 --- a/src/app/api-connector/group.service.ts +++ b/src/app/api-connector/group.service.ts @@ -195,6 +195,8 @@ export class GroupService { } getGroupApplications(group: number | string): Observable { + console.log(group); + return this.http.get(`${ApiSettings.getApiBaseURL()}projects/${group}/applications/`, { withCredentials: true, }); diff --git a/src/app/applications/application.model/application.model.ts b/src/app/applications/application.model/application.model.ts index d099604563..9a7cb89900 100644 --- a/src/app/applications/application.model/application.model.ts +++ b/src/app/applications/application.model/application.model.ts @@ -92,7 +92,7 @@ export class Application { migrate_to_simple_vm: boolean = false; - is_project_selected:boolean=false; + is_project_selected: boolean = false; constructor(aj?: Partial) { this.dissemination = new ApplicationDissemination(null); @@ -192,6 +192,10 @@ export class Application { } else return 0; } + public isApproved(): boolean { + return this.project_application_statuses.includes(Application_States.APPROVED); + } + public setFlavorInFlavors(flavor_param: Flavor, counter: number): void { const idx: number = this.flavors.findIndex((fl: Flavor): boolean => fl.name === flavor_param.name); if (idx !== -1) { diff --git a/src/app/projectmanagement/overview.component.ts b/src/app/projectmanagement/overview.component.ts index df1e7afd39..55398445c5 100644 --- a/src/app/projectmanagement/overview.component.ts +++ b/src/app/projectmanagement/overview.component.ts @@ -684,32 +684,36 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements * Get all user applications for a project. */ getUserProjectApplications(): void { - this.memberApplicationsLoaded = false; - this.subscription.add( - this.groupService - .getGroupApplications(this.project_application.project_application_perun_id) - .subscribe((applications: any): void => { - const newProjectApplications: ProjectMemberApplication[] = []; - if (applications.length === 0) { - this.project_application.project_application_member_applications = []; + if (this.project_application.isApproved() && this.project_application.project_application_perun_id) { + this.memberApplicationsLoaded = false; + this.subscription.add( + this.groupService + .getGroupApplications(this.project_application.project_application_perun_id) + .subscribe((applications: any): void => { + const newProjectApplications: ProjectMemberApplication[] = []; + if (applications.length === 0) { + this.project_application.project_application_member_applications = []; - this.memberApplicationsLoaded = true; - } - for (const application of applications) { - const dateApplicationCreated: moment.Moment = moment(application['createdAt'], 'YYYY-MM-DD HH:mm:ss.SSS'); - const membername: string = application['displayName']; - - const newMemberApplication: ProjectMemberApplication = new ProjectMemberApplication( - application['id'], - membername, - `${dateApplicationCreated.date()}.${dateApplicationCreated.month() + 1}.${dateApplicationCreated.year()}`, - ); - newProjectApplications.push(newMemberApplication); - this.project_application.project_application_member_applications = newProjectApplications; - this.memberApplicationsLoaded = true; - } - }), - ); + this.memberApplicationsLoaded = true; + } + for (const application of applications) { + const dateApplicationCreated: moment.Moment = moment(application['createdAt'], 'YYYY-MM-DD HH:mm:ss.SSS'); + const membername: string = application['displayName']; + + const newMemberApplication: ProjectMemberApplication = new ProjectMemberApplication( + application['id'], + membername, + `${dateApplicationCreated.date()}.${ + dateApplicationCreated.month() + 1 + }.${dateApplicationCreated.year()}`, + ); + newProjectApplications.push(newMemberApplication); + this.project_application.project_application_member_applications = newProjectApplications; + this.memberApplicationsLoaded = true; + } + }), + ); + } } setSupportMails(project: Application): void { From 6dae0cfed8fba1c5d57cb5ce0fbac2e90918d392 Mon Sep 17 00:00:00 2001 From: dweinholz Date: Tue, 25 Apr 2023 12:31:35 +0200 Subject: [PATCH 2/4] feat(VirtualMachine):added stopped vm info --- .../modals/stop-vm/stop-vm.component.html | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/app/virtualmachines/modals/stop-vm/stop-vm.component.html b/src/app/virtualmachines/modals/stop-vm/stop-vm.component.html index 461658f304..89572449ef 100644 --- a/src/app/virtualmachines/modals/stop-vm/stop-vm.component.html +++ b/src/app/virtualmachines/modals/stop-vm/stop-vm.component.html @@ -1,26 +1,27 @@ - From 4bdc850a529a11bcf0bda38882264839cb116d65 Mon Sep 17 00:00:00 2001 From: vktrrdk Date: Wed, 26 Apr 2023 10:43:14 +0200 Subject: [PATCH 3/4] linting --- .../project-email-modal.component.ts | 103 +++++++++--------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts index e810f9c2a6..8eacbca5dd 100644 --- a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts +++ b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts @@ -1,54 +1,57 @@ -import {Component, EventEmitter, Input, OnInit} from '@angular/core'; -import {Application} from '../../../../applications/application.model/application.model'; -import {BsModalRef} from 'ngx-bootstrap/modal'; -import {VoService} from '../../../../api-connector/vo.service'; -import {IResponseTemplate} from '../../../../api-connector/response-template'; +import { + Component, EventEmitter, Input, OnDestroy, OnInit, +} from '@angular/core'; +import { BsModalRef } from 'ngx-bootstrap/modal'; +import { Application } from '../../../../applications/application.model/application.model'; +import { VoService } from '../../../../api-connector/vo.service'; +import { IResponseTemplate } from '../../../../api-connector/response-template'; @Component({ - selector: 'app-project-email-modal', - templateUrl: './project-email-modal.component.html', - styleUrls: ['./projext-email-modal.component.scss'], - + selector: 'app-project-email-modal', + templateUrl: './project-email-modal.component.html', + styleUrls: ['./projext-email-modal.component.scss'], }) -export class ProjectEmailModalComponent implements OnInit { - - //currently only for vo - @Input() selectedProjects: Application[]; - emailAdminsOnly: boolean; - emailSubject: string; - emailReply: string; - emailText: string; - templates: string[]; - - public mailSuccesfullySent: EventEmitter = new EventEmitter(); - - constructor(public bsModalRef: BsModalRef, private voService: VoService) { - // eslint-disable-next-line no-empty-function - } - - ngOnInit() { - this.getMailTemplates() - } - - getMailTemplates(): void { - this.voService.getMailTemplates().subscribe((res: string[]) => { - this.templates = res - }) - } - - sentProjectsMail(): void { - const project_ids = this.selectedProjects.map((pr: Application) => { - return pr.project_application_perun_id; - }); - - this.voService.sendMailToProjects(project_ids, this.emailSubject, this.emailText, this.emailAdminsOnly, this.emailReply).subscribe((res: IResponseTemplate) => { - this.mailSuccesfullySent.emit(res.value as boolean) - }, () => { - this.mailSuccesfullySent.emit(false) - }) - } - - ngOnDestroy(): void { - this.bsModalRef.hide(); - } +export class ProjectEmailModalComponent implements OnInit, OnDestroy { + // currently only for vo + @Input() selectedProjects: Application[]; + emailAdminsOnly: boolean; + emailSubject: string; + emailReply: string; + emailText: string; + templates: string[]; + + public mailSuccesfullySent: EventEmitter = new EventEmitter(); + + constructor(public bsModalRef: BsModalRef, private voService: VoService) { + // eslint-disable-next-line no-empty-function + } + + ngOnInit() { + this.getMailTemplates(); + } + + getMailTemplates(): void { + this.voService.getMailTemplates().subscribe((res: string[]) => { + this.templates = res; + }); + } + + sentProjectsMail(): void { + const project_ids = this.selectedProjects.map((pr: Application) => pr.project_application_perun_id); + + this.voService + .sendMailToProjects(project_ids, this.emailSubject, this.emailText, this.emailAdminsOnly, this.emailReply) + .subscribe( + (res: IResponseTemplate) => { + this.mailSuccesfullySent.emit(res.value as boolean); + }, + () => { + this.mailSuccesfullySent.emit(false); + }, + ); + } + + ngOnDestroy(): void { + this.bsModalRef.hide(); + } } From a17b1654d91a2212ec99c4af1ea7907f17c25d00 Mon Sep 17 00:00:00 2001 From: dweinholz Date: Wed, 26 Apr 2023 14:05:40 +0200 Subject: [PATCH 4/4] fixed linting --- src/app/api-connector/vo.service.ts | 472 +++---- .../application.model/application.model.ts | 2 +- .../project-email-modal.component.html | 233 ++-- .../project-email-modal.component.ts | 103 +- .../services/project-sort.service.ts | 390 +++--- .../shared_modules/shared-module.module.ts | 65 +- src/app/vo_manager/VoManager.module.ts | 36 +- src/app/vo_manager/VoOverviewComponent.ts | 1106 ++++++++--------- 8 files changed, 1203 insertions(+), 1204 deletions(-) diff --git a/src/app/api-connector/vo.service.ts b/src/app/api-connector/vo.service.ts index dc69559cd8..dd921dc8fe 100644 --- a/src/app/api-connector/vo.service.ts +++ b/src/app/api-connector/vo.service.ts @@ -1,241 +1,245 @@ -import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; -import {HttpClient, HttpParams} from '@angular/common/http'; -import {map} from 'rxjs/operators'; -import {ApiSettings} from './api-settings.service'; -import {IResponseTemplate} from './response-template'; -import {Resources} from '../vo_manager/resources/resources'; -import {ProjectMember} from '../projectmanagement/project_member.model'; -import {Application} from '../applications/application.model/application.model'; -import {MaintenanceTimeFrame} from '../vo_manager/maintenance/maintenanceTimeFrame.model'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { map } from 'rxjs/operators'; +import { ApiSettings } from './api-settings.service'; +import { IResponseTemplate } from './response-template'; +import { Resources } from '../vo_manager/resources/resources'; +import { ProjectMember } from '../projectmanagement/project_member.model'; +import { Application } from '../applications/application.model/application.model'; +import { MaintenanceTimeFrame } from '../vo_manager/maintenance/maintenanceTimeFrame.model'; /** * Service which provides vo methods. */ @Injectable() export class VoService { - constructor(private http: HttpClient) { - this.http = http; - } - - sendTestError(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/test_bug/`, { - withCredentials: true, - }); - } - - isVo(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/current/status/`, { - withCredentials: true, - }); - } - - getNewsletterSubscriptionCounter(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}newsletter/subscription/counter/`, { - withCredentials: true, - }); - } - - terminateProject(groupId: number | string): Observable { - return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${groupId}/`, { - withCredentials: true, - }); - } - - removeResourceFromGroup(groupid: number | string): Observable { - return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/resource/`, { - withCredentials: true, - }); - } - - resumeProject(groupid: number | string): Observable { - return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/resource/`, null, { - withCredentials: true, - }); - } - - getAllGroupsWithDetails(): Observable { - return this.http - .get(`${ApiSettings.getApiBaseURL()}vo/projects/details/`, { - withCredentials: true, - }) - .pipe( - map((applications: Application[]): Application[] => applications.map((application: Application): Application => new Application(application))), - ); - } - - getProjectStatus(groupid: number | string): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/status/`, { - withCredentials: true, - }); - } - - getVoProjectResources(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/resources/`, { - withCredentials: true, - }); - } - - getVoProjectResourcesTimeframes(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/resources/timeFrames/`, { - withCredentials: true, - }); - } - - getVoProjectDates(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/dates/`, { - withCredentials: true, - }); - } - - getVoProjectCounter(): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/counter/`, { - withCredentials: true, - }); - } - - setProjectStatus(groupid: number | string, status: number): Observable { - const params: HttpParams = new HttpParams().set('status', status.toString()); - - return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/status/`, params, { - withCredentials: true, - }); - } - - sendNewsletterToVo( - subject: string, - message: string, - type: string, - adminsOnly: boolean, - reply?: string, - ): Observable { - const params: HttpParams = new HttpParams() - .set('subject', subject) - .set('message', message) - .set('admins_only', adminsOnly) - .set('reply', reply) - .set('type', type); - - return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/current/newsletter/`, params, { - withCredentials: true, - }); - } - - sendMailToVo( - subject: string, - message: string, - facility: string, - type: string, - adminsOnly: boolean, - expiredTemplate: boolean, - removalDate: Date, - reply?: string, - ): Observable { - const params: HttpParams = new HttpParams() - .set('subject', subject) - .set('message', message) - .set('admins_only', adminsOnly) - .set('reply', reply) - .set('facility', facility) - .set('expired_template', expiredTemplate) - .set('removal_date', removalDate.toUTCString()) - .set('type', type); - - return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/current/voMail/`, params, { - withCredentials: true, - }); - } - - sendMailToProjects( - projectIds: (string | number)[], - subject: string, - message: string, - adminsOnly: boolean, - reply?: string, - ): Observable { - - - return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/current/voMail/projects/`, - {project_ids: projectIds, subject: subject, message: message, adminsOnly: adminsOnly, reply: reply}, { - withCredentials: true, - }); - } - - - getMailTemplates(): Observable { - - - return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/current/voMail/projects/templates/`, { - withCredentials: true, - }); - } - - /** - * Get members of a project with emails. - * - * @param groupid id of the group - * @returns - */ - getVoGroupRichMembers(groupid: number | string): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/members/`, { - withCredentials: true, - }); - } - - setCurrentUserProcessingVoManager(application_id: number | string): Observable { - return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${application_id}/vo_manager/`, null, { - withCredentials: true, - }); - } - - unsetProcessingVoManager(application_id: number | string): Observable { - return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${application_id}/vo_manager/`, { - withCredentials: true, - }); - } - - setProtected(groupid: number | string, set: boolean): Observable { - const parameters: HttpParams = new HttpParams().set('action', set ? 'set' : 'unset'); - - return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/protected/`, { - withCredentials: true, - params: parameters, - }); - } - - declineTermination(groupid: number | string): Observable { - return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/termination/decline/`, { - withCredentials: true, - }); - } - - loadMaintenanceTimeFrames(): Observable { - return this.http - .get(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/`, { - withCredentials: true, - }) - .pipe( - map((maintenanceTimeFrames: MaintenanceTimeFrame[]): MaintenanceTimeFrame[] => maintenanceTimeFrames.map( - (maintenanceTimeFrame: MaintenanceTimeFrame): MaintenanceTimeFrame => new MaintenanceTimeFrame(maintenanceTimeFrame), - )), - ); - } - - addMaintenanceTimeFrame(timeframe: MaintenanceTimeFrame): Observable { - const params: HttpParams = new HttpParams() - .set('start_time', timeframe.start_time.toJSON()) - .set('end_time', timeframe.end_time.toJSON()) - .set('name', timeframe.name) - .set('message', timeframe.message); - - return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/`, params, { - withCredentials: true, - }); - } - - deleteMaintenanceTimeFrame(timeframe: MaintenanceTimeFrame): Observable { - return this.http.delete(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/${timeframe.id}/`, { - withCredentials: true, - }); - } + constructor(private http: HttpClient) { + this.http = http; + } + + sendTestError(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/test_bug/`, { + withCredentials: true, + }); + } + + isVo(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/current/status/`, { + withCredentials: true, + }); + } + + getNewsletterSubscriptionCounter(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}newsletter/subscription/counter/`, { + withCredentials: true, + }); + } + + terminateProject(groupId: number | string): Observable { + return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${groupId}/`, { + withCredentials: true, + }); + } + + removeResourceFromGroup(groupid: number | string): Observable { + return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/resource/`, { + withCredentials: true, + }); + } + + resumeProject(groupid: number | string): Observable { + return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/resource/`, null, { + withCredentials: true, + }); + } + + getAllGroupsWithDetails(): Observable { + return this.http + .get(`${ApiSettings.getApiBaseURL()}vo/projects/details/`, { + withCredentials: true, + }) + .pipe( + map((applications: Application[]): Application[] => applications.map((application: Application): Application => new Application(application))), + ); + } + + getProjectStatus(groupid: number | string): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/status/`, { + withCredentials: true, + }); + } + + getVoProjectResources(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/resources/`, { + withCredentials: true, + }); + } + + getVoProjectResourcesTimeframes(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/resources/timeFrames/`, { + withCredentials: true, + }); + } + + getVoProjectDates(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/dates/`, { + withCredentials: true, + }); + } + + getVoProjectCounter(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/counter/`, { + withCredentials: true, + }); + } + + setProjectStatus(groupid: number | string, status: number): Observable { + const params: HttpParams = new HttpParams().set('status', status.toString()); + + return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/status/`, params, { + withCredentials: true, + }); + } + + sendNewsletterToVo( + subject: string, + message: string, + type: string, + adminsOnly: boolean, + reply?: string, + ): Observable { + const params: HttpParams = new HttpParams() + .set('subject', subject) + .set('message', message) + .set('admins_only', adminsOnly) + .set('reply', reply) + .set('type', type); + + return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/current/newsletter/`, params, { + withCredentials: true, + }); + } + + sendMailToVo( + subject: string, + message: string, + facility: string, + type: string, + adminsOnly: boolean, + expiredTemplate: boolean, + removalDate: Date, + reply?: string, + ): Observable { + const params: HttpParams = new HttpParams() + .set('subject', subject) + .set('message', message) + .set('admins_only', adminsOnly) + .set('reply', reply) + .set('facility', facility) + .set('expired_template', expiredTemplate) + .set('removal_date', removalDate.toUTCString()) + .set('type', type); + + return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/current/voMail/`, params, { + withCredentials: true, + }); + } + + sendMailToProjects( + projectIds: (string | number)[], + subject: string, + message: string, + adminsOnly: boolean, + reply?: string, + ): Observable { + return this.http.post( + `${ApiSettings.getApiBaseURL()}voManagers/current/voMail/projects/`, + { + project_ids: projectIds, + subject, + message, + adminsOnly, + reply, + }, + { + withCredentials: true, + }, + ); + } + + getMailTemplates(): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}voManagers/current/voMail/projects/templates/`, { + withCredentials: true, + }); + } + + /** + * Get members of a project with emails. + * + * @param groupid id of the group + * @returns + */ + getVoGroupRichMembers(groupid: number | string): Observable { + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/members/`, { + withCredentials: true, + }); + } + + setCurrentUserProcessingVoManager(application_id: number | string): Observable { + return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${application_id}/vo_manager/`, null, { + withCredentials: true, + }); + } + + unsetProcessingVoManager(application_id: number | string): Observable { + return this.http.delete(`${ApiSettings.getApiBaseURL()}vo/projects/${application_id}/vo_manager/`, { + withCredentials: true, + }); + } + + setProtected(groupid: number | string, set: boolean): Observable { + const parameters: HttpParams = new HttpParams().set('action', set ? 'set' : 'unset'); + + return this.http.get(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/protected/`, { + withCredentials: true, + params: parameters, + }); + } + + declineTermination(groupid: number | string): Observable { + return this.http.post(`${ApiSettings.getApiBaseURL()}vo/projects/${groupid}/termination/decline/`, { + withCredentials: true, + }); + } + + loadMaintenanceTimeFrames(): Observable { + return this.http + .get(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/`, { + withCredentials: true, + }) + .pipe( + map((maintenanceTimeFrames: MaintenanceTimeFrame[]): MaintenanceTimeFrame[] => maintenanceTimeFrames.map( + (maintenanceTimeFrame: MaintenanceTimeFrame): MaintenanceTimeFrame => new MaintenanceTimeFrame(maintenanceTimeFrame), + )), + ); + } + + addMaintenanceTimeFrame(timeframe: MaintenanceTimeFrame): Observable { + const params: HttpParams = new HttpParams() + .set('start_time', timeframe.start_time.toJSON()) + .set('end_time', timeframe.end_time.toJSON()) + .set('name', timeframe.name) + .set('message', timeframe.message); + + return this.http.post(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/`, params, { + withCredentials: true, + }); + } + + deleteMaintenanceTimeFrame(timeframe: MaintenanceTimeFrame): Observable { + return this.http.delete(`${ApiSettings.getApiBaseURL()}voManagers/maintenance/${timeframe.id}/`, { + withCredentials: true, + }); + } } diff --git a/src/app/applications/application.model/application.model.ts b/src/app/applications/application.model/application.model.ts index d099604563..1cc01acc0f 100644 --- a/src/app/applications/application.model/application.model.ts +++ b/src/app/applications/application.model/application.model.ts @@ -92,7 +92,7 @@ export class Application { migrate_to_simple_vm: boolean = false; - is_project_selected:boolean=false; + is_project_selected: boolean = false; constructor(aj?: Partial) { this.dissemination = new ApplicationDissemination(null); diff --git a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html index cea130c303..e4a0599ece 100644 --- a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html +++ b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html @@ -1,127 +1,120 @@ diff --git a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts index e810f9c2a6..37309e435b 100644 --- a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts +++ b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.ts @@ -1,54 +1,57 @@ -import {Component, EventEmitter, Input, OnInit} from '@angular/core'; -import {Application} from '../../../../applications/application.model/application.model'; -import {BsModalRef} from 'ngx-bootstrap/modal'; -import {VoService} from '../../../../api-connector/vo.service'; -import {IResponseTemplate} from '../../../../api-connector/response-template'; +import { + Component, EventEmitter, Input, OnDestroy, OnInit, +} from '@angular/core'; +import { BsModalRef } from 'ngx-bootstrap/modal'; +import { Application } from '../../../../applications/application.model/application.model'; +import { VoService } from '../../../../api-connector/vo.service'; +import { IResponseTemplate } from '../../../../api-connector/response-template'; @Component({ - selector: 'app-project-email-modal', - templateUrl: './project-email-modal.component.html', - styleUrls: ['./projext-email-modal.component.scss'], - + selector: 'app-project-email-modal', + templateUrl: './project-email-modal.component.html', + styleUrls: ['./projext-email-modal.component.scss'], }) -export class ProjectEmailModalComponent implements OnInit { - - //currently only for vo - @Input() selectedProjects: Application[]; - emailAdminsOnly: boolean; - emailSubject: string; - emailReply: string; - emailText: string; - templates: string[]; - - public mailSuccesfullySent: EventEmitter = new EventEmitter(); - - constructor(public bsModalRef: BsModalRef, private voService: VoService) { - // eslint-disable-next-line no-empty-function - } - - ngOnInit() { - this.getMailTemplates() - } - - getMailTemplates(): void { - this.voService.getMailTemplates().subscribe((res: string[]) => { - this.templates = res - }) - } - - sentProjectsMail(): void { - const project_ids = this.selectedProjects.map((pr: Application) => { - return pr.project_application_perun_id; - }); - - this.voService.sendMailToProjects(project_ids, this.emailSubject, this.emailText, this.emailAdminsOnly, this.emailReply).subscribe((res: IResponseTemplate) => { - this.mailSuccesfullySent.emit(res.value as boolean) - }, () => { - this.mailSuccesfullySent.emit(false) - }) - } - - ngOnDestroy(): void { - this.bsModalRef.hide(); - } +export class ProjectEmailModalComponent implements OnDestroy, OnInit { + // currently only for vo + @Input() selectedProjects: Application[]; + emailAdminsOnly: boolean; + emailSubject: string; + emailReply: string; + emailText: string; + templates: string[]; + + public event: EventEmitter = new EventEmitter(); + + constructor(public bsModalRef: BsModalRef, private voService: VoService) { + // eslint-disable-next-line no-empty-function + } + + ngOnInit() { + this.getMailTemplates(); + } + + getMailTemplates(): void { + this.voService.getMailTemplates().subscribe((res: string[]) => { + this.templates = res; + }); + } + + sentProjectsMail(): void { + const project_ids = this.selectedProjects.map((pr: Application) => pr.project_application_perun_id); + + this.voService + .sendMailToProjects(project_ids, this.emailSubject, this.emailText, this.emailAdminsOnly, this.emailReply) + .subscribe( + (res: IResponseTemplate) => { + this.event.emit(res.value as boolean); + }, + () => { + this.event.emit(false); + }, + ); + } + + ngOnDestroy(): void { + this.bsModalRef.hide(); + } } diff --git a/src/app/shared/shared_modules/services/project-sort.service.ts b/src/app/shared/shared_modules/services/project-sort.service.ts index cb3faaf959..0a84b54130 100644 --- a/src/app/shared/shared_modules/services/project-sort.service.ts +++ b/src/app/shared/shared_modules/services/project-sort.service.ts @@ -1,207 +1,207 @@ -import {Injectable} from '@angular/core'; +import { Injectable } from '@angular/core'; import { - BehaviorSubject, delay, Observable, of, Subject, + BehaviorSubject, delay, Observable, of, Subject, } from 'rxjs'; -import {debounceTime, switchMap, tap} from 'rxjs/operators'; -import {Application_States} from '../baseClass/abstract-base-class'; -import {Application} from '../../../applications/application.model/application.model'; +import { debounceTime, switchMap, tap } from 'rxjs/operators'; +import { Application_States } from '../baseClass/abstract-base-class'; +import { Application } from '../../../applications/application.model/application.model'; import { - compare, SortColumn, SortDirection, State, + compare, SortColumn, SortDirection, State, } from '../directives/nbd-sortable-header.directive'; interface SearchResult { - sortedApplications: Application[] - total: number + sortedApplications: Application[] + total: number } @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class ProjectSortService { - public filterStatusList: number[] = []; - public showSimpleVM: boolean = true; - public showOpenStack: boolean = true; - private _loading$ = new BehaviorSubject(true); - private _search$ = new Subject(); - private _applications$ = new BehaviorSubject([]); - private _total$ = new BehaviorSubject(0); - private _applications: Application[] = []; - public sorted_applications: Application[] = []; - - _initiateFilterStatusList(): void { - this.filterStatusList = [ - Application_States.ACTIVE, - Application_States.SUSPENDED, - // Application_States.DELETED, - Application_States.EXPIRED, - Application_States.WAIT_FOR_CONFIRMATION, - Application_States.TERMINATION_REQUESTED, - Application_States.EXPIRES_SOON, - ]; - } - - get applications$() { - return this._applications$.asObservable(); - } - - get total$() { - return this._total$.asObservable(); - } - - get loading$() { - return this._loading$.asObservable(); - } - - set page(page: number) { - this._set({page}); - } - - get page() { - return this._state.page; - } - - get pageSize() { - return this._state.pageSize; - } - - set pageSize(pageSize: number) { - this._set({pageSize}); - } - - get searchTerm() { - return this._state.searchTerm; - } - - set searchTerm(searchTerm: string) { - searchTerm = searchTerm.trim(); - this._set({searchTerm}); - } - - set sortColumn(sortColumn: SortColumn) { - this._set({sortColumn}); - } - - set sortDirection(sortDirection: SortDirection) { - this._set({sortDirection}); - } - - set applications(applications: Application[]) { - this._applications = applications; - this._search$.next(); - } - - get applications() { - return this._applications - } - - initiateSearch(): void { - this._search$.next(); - } - - private _state: State = { - page: 1, - pageSize: 10, - searchTerm: '', - sortColumn: '', - sortDirection: '', - }; - - private _set(patch: Partial) { - Object.assign(this._state, patch); - this._search$.next(); - } - - constructor() { - this.applications = []; - this._initiateFilterStatusList(); - this._search$ - .pipe( - tap(() => this._loading$.next(true)), - debounceTime(200), - switchMap(() => this._search()), - delay(100), - tap(() => this._loading$.next(false)), - ) - .subscribe(result => { - this._applications$.next(result.sortedApplications); - this._total$.next(result.total); - }); - - this._search$.next(); - } - - addOrRemoveFromFilterStatusList(status: Application_States) { - const idx = this.filterStatusList.indexOf(status); - if (idx === -1) { - this.filterStatusList.push(status); - } else { - this.filterStatusList.splice(idx, 1); - } - this._search$.next(); - } - - matches(text: string, project: Application): boolean { - const term = text.toLowerCase(); - if ( - (!this.showSimpleVM && !project.project_application_openstack_project) - || (!this.showOpenStack && project.project_application_openstack_project) - ) { - return false; - } - - if (this.filterStatusList) { - const status_match: boolean = project.project_application_statuses.some(r => this.filterStatusList.includes(r)); - if (!status_match) { - return false; - } - } - - return ( - project.project_application_shortname.toLowerCase().includes(term) - || project.project_application_perun_id.toString().toLowerCase().includes(term) - || project.project_application_current_credits.toString().toLowerCase().includes(term) - || project.project_application_initial_credits.toString().toLowerCase().includes(term) - || project?.project_application_compute_center?.Name.toString().toLowerCase().includes(term) - || project.project_application_total_ram.toString().toLowerCase().includes(term) - || project.project_application_total_cores.toString().toLowerCase().includes(term) - || project.project_application_total_gpu.toString().toLowerCase().includes(term) - || project.project_application_name.toString().toLowerCase().includes(term) - ); - } - - sort(applications: Application[], column: SortColumn, direction: string): Application[] { - if (direction === '' || column === '') { - return applications; - } else { - return [...applications].sort((a, b) => { - // if (typeof a[column] == 'string' || typeof a[column] == 'number') { - - // @ts-ignore - const res = compare(a[column], b[column]); - - return direction === 'asc' ? res : -res; - // } - }); - } - } - - private _search(): Observable { - const { - sortColumn, sortDirection, pageSize, page, searchTerm, - } = this._state; - - // 1. sort - let sortedApplications = this.sort(this._applications, sortColumn, sortDirection); - - // 2. filter - sortedApplications = sortedApplications.filter(app => this.matches(searchTerm, app)); - this.sorted_applications = sortedApplications; - - const total = sortedApplications.length; - - // 3. paginate - sortedApplications = sortedApplications.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize); - - return of({sortedApplications, total}); - } + public filterStatusList: number[] = []; + public showSimpleVM: boolean = true; + public showOpenStack: boolean = true; + private _loading$ = new BehaviorSubject(true); + private _search$ = new Subject(); + private _applications$ = new BehaviorSubject([]); + private _total$ = new BehaviorSubject(0); + private _applications: Application[] = []; + public sorted_applications: Application[] = []; + + _initiateFilterStatusList(): void { + this.filterStatusList = [ + Application_States.ACTIVE, + Application_States.SUSPENDED, + // Application_States.DELETED, + Application_States.EXPIRED, + Application_States.WAIT_FOR_CONFIRMATION, + Application_States.TERMINATION_REQUESTED, + Application_States.EXPIRES_SOON, + ]; + } + + get applications$() { + return this._applications$.asObservable(); + } + + get total$() { + return this._total$.asObservable(); + } + + get loading$() { + return this._loading$.asObservable(); + } + + set page(page: number) { + this._set({ page }); + } + + get page() { + return this._state.page; + } + + get pageSize() { + return this._state.pageSize; + } + + set pageSize(pageSize: number) { + this._set({ pageSize }); + } + + get searchTerm() { + return this._state.searchTerm; + } + + set searchTerm(searchTerm: string) { + searchTerm = searchTerm.trim(); + this._set({ searchTerm }); + } + + set sortColumn(sortColumn: SortColumn) { + this._set({ sortColumn }); + } + + set sortDirection(sortDirection: SortDirection) { + this._set({ sortDirection }); + } + + set applications(applications: Application[]) { + this._applications = applications; + this._search$.next(); + } + + get applications() { + return this._applications; + } + + initiateSearch(): void { + this._search$.next(); + } + + private _state: State = { + page: 1, + pageSize: 10, + searchTerm: '', + sortColumn: '', + sortDirection: '', + }; + + private _set(patch: Partial) { + Object.assign(this._state, patch); + this._search$.next(); + } + + constructor() { + this.applications = []; + this._initiateFilterStatusList(); + this._search$ + .pipe( + tap(() => this._loading$.next(true)), + debounceTime(200), + switchMap(() => this._search()), + delay(100), + tap(() => this._loading$.next(false)), + ) + .subscribe(result => { + this._applications$.next(result.sortedApplications); + this._total$.next(result.total); + }); + + this._search$.next(); + } + + addOrRemoveFromFilterStatusList(status: Application_States) { + const idx = this.filterStatusList.indexOf(status); + if (idx === -1) { + this.filterStatusList.push(status); + } else { + this.filterStatusList.splice(idx, 1); + } + this._search$.next(); + } + + matches(text: string, project: Application): boolean { + const term = text.toLowerCase(); + if ( + (!this.showSimpleVM && !project.project_application_openstack_project) + || (!this.showOpenStack && project.project_application_openstack_project) + ) { + return false; + } + + if (this.filterStatusList) { + const status_match: boolean = project.project_application_statuses.some(r => this.filterStatusList.includes(r)); + if (!status_match) { + return false; + } + } + + return ( + project.project_application_shortname.toLowerCase().includes(term) + || project.project_application_perun_id.toString().toLowerCase().includes(term) + || project.project_application_current_credits.toString().toLowerCase().includes(term) + || project.project_application_initial_credits.toString().toLowerCase().includes(term) + || project?.project_application_compute_center?.Name.toString().toLowerCase().includes(term) + || project.project_application_total_ram.toString().toLowerCase().includes(term) + || project.project_application_total_cores.toString().toLowerCase().includes(term) + || project.project_application_total_gpu.toString().toLowerCase().includes(term) + || project.project_application_name.toString().toLowerCase().includes(term) + ); + } + + sort(applications: Application[], column: SortColumn, direction: string): Application[] { + if (direction === '' || column === '') { + return applications; + } else { + return [...applications].sort((a, b) => { + // if (typeof a[column] == 'string' || typeof a[column] == 'number') { + + // @ts-ignore + const res = compare(a[column], b[column]); + + return direction === 'asc' ? res : -res; + // } + }); + } + } + + private _search(): Observable { + const { + sortColumn, sortDirection, pageSize, page, searchTerm, + } = this._state; + + // 1. sort + let sortedApplications = this.sort(this._applications, sortColumn, sortDirection); + + // 2. filter + sortedApplications = sortedApplications.filter(app => this.matches(searchTerm, app)); + this.sorted_applications = sortedApplications; + + const total = sortedApplications.length; + + // 3. paginate + sortedApplications = sortedApplications.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize); + + return of({ sortedApplications, total }); + } } diff --git a/src/app/shared/shared_modules/shared-module.module.ts b/src/app/shared/shared_modules/shared-module.module.ts index 21aacbc5e6..7267286582 100644 --- a/src/app/shared/shared_modules/shared-module.module.ts +++ b/src/app/shared/shared_modules/shared-module.module.ts @@ -1,39 +1,38 @@ -import {NgModule} from '@angular/core'; -import {CommonModule} from '@angular/common'; -import {ModalModule} from 'ngx-bootstrap/modal'; -import {ProgressModule, ToastModule} from '@coreui/angular'; -import {ApplicationBaseClassComponent} from './baseClass/application-base-class.component'; -import {NotificationModalComponent} from '../modal/notification-modal'; -import {InformationToastComponent} from '../toaster/information-toast.component'; -import {ConfirmationModalComponent} from '../modal/confirmation-modal.component'; -import {MigrationInformationComponent} from './migration-information/migration-information.component'; -import {ApplicationBadgesComponent} from './components/applications/application-badges/application-badges.component'; -import {ProjectEmailModalComponent} from '../modal/email/project-email-modal/project-email-modal.component'; -import {FormsModule} from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ModalModule } from 'ngx-bootstrap/modal'; +import { ProgressModule, ToastModule } from '@coreui/angular'; +import { FormsModule } from '@angular/forms'; +import { ApplicationBaseClassComponent } from './baseClass/application-base-class.component'; +import { NotificationModalComponent } from '../modal/notification-modal'; +import { InformationToastComponent } from '../toaster/information-toast.component'; +import { ConfirmationModalComponent } from '../modal/confirmation-modal.component'; +import { MigrationInformationComponent } from './migration-information/migration-information.component'; +import { ApplicationBadgesComponent } from './components/applications/application-badges/application-badges.component'; +import { ProjectEmailModalComponent } from '../modal/email/project-email-modal/project-email-modal.component'; /** * Shared module. */ @NgModule({ - exports: [ - ApplicationBaseClassComponent, - NotificationModalComponent, - ConfirmationModalComponent, - InformationToastComponent, - MigrationInformationComponent, - ApplicationBadgesComponent, - ProjectEmailModalComponent - ], - imports: [CommonModule, ModalModule.forRoot(), ToastModule, ProgressModule, FormsModule], - declarations: [ - ApplicationBaseClassComponent, - NotificationModalComponent, - ConfirmationModalComponent, - InformationToastComponent, - MigrationInformationComponent, - ApplicationBadgesComponent, - ProjectEmailModalComponent - ], + exports: [ + ApplicationBaseClassComponent, + NotificationModalComponent, + ConfirmationModalComponent, + InformationToastComponent, + MigrationInformationComponent, + ApplicationBadgesComponent, + ProjectEmailModalComponent, + ], + imports: [CommonModule, ModalModule.forRoot(), ToastModule, ProgressModule, FormsModule], + declarations: [ + ApplicationBaseClassComponent, + NotificationModalComponent, + ConfirmationModalComponent, + InformationToastComponent, + MigrationInformationComponent, + ApplicationBadgesComponent, + ProjectEmailModalComponent, + ], }) -export class SharedModuleModule { -} +export class SharedModuleModule {} diff --git a/src/app/vo_manager/VoManager.module.ts b/src/app/vo_manager/VoManager.module.ts index 770e9d1b11..ec169b77fa 100644 --- a/src/app/vo_manager/VoManager.module.ts +++ b/src/app/vo_manager/VoManager.module.ts @@ -6,6 +6,7 @@ import { CommonModule } from '@angular/common'; import { ModalModule } from 'ngx-bootstrap/modal'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NgbPaginationModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; +import { BadgeComponent } from '@coreui/angular'; import { VoManagerRoutingModule } from './VoManager-routing.module'; import { VoOverviewComponent } from './VoOverviewComponent'; import { VoGuardService } from './vo-guard.service'; @@ -21,29 +22,28 @@ import { MaintenanceComponent } from './maintenance/maintenance.component'; import { DatePickerComponent } from '../shared/datepicking/datepicker.component'; import { TimepickerComponent } from '../shared/datepicking/timepicker.component'; import { SharedModuleModule } from '../shared/shared_modules/shared-module.module'; -import {BadgeComponent} from '@coreui/angular'; /** * VO Manager module. */ @NgModule({ - imports: [ - VoManagerRoutingModule, - TabsModule, - FormsModule, - CommonModule, - ModalModule.forRoot(), - ProjectManagementModule, - PipeModuleModule, - NgbTypeaheadModule, - ReactiveFormsModule, - SharedDirectivesModule, - NgbPaginationModule, - DatePickerComponent, - TimepickerComponent, - SharedModuleModule, - BadgeComponent, - ], + imports: [ + VoManagerRoutingModule, + TabsModule, + FormsModule, + CommonModule, + ModalModule.forRoot(), + ProjectManagementModule, + PipeModuleModule, + NgbTypeaheadModule, + ReactiveFormsModule, + SharedDirectivesModule, + NgbPaginationModule, + DatePickerComponent, + TimepickerComponent, + SharedModuleModule, + BadgeComponent, + ], declarations: [ VoOverviewComponent, ResourcesComponent, diff --git a/src/app/vo_manager/VoOverviewComponent.ts b/src/app/vo_manager/VoOverviewComponent.ts index 7d14a3a818..f4e84ce0b8 100644 --- a/src/app/vo_manager/VoOverviewComponent.ts +++ b/src/app/vo_manager/VoOverviewComponent.ts @@ -1,577 +1,577 @@ -import {ngxCsv} from 'ngx-csv/ngx-csv'; +import { ngxCsv } from 'ngx-csv/ngx-csv'; import { - Component, OnInit, QueryList, ViewChildren, + Component, OnInit, QueryList, ViewChild, ViewChildren, } from '@angular/core'; -import {DomSanitizer} from '@angular/platform-browser'; -import {map, Observable, take} from 'rxjs'; -import {VoService} from '../api-connector/vo.service'; -import {ProjectMember} from '../projectmanagement/project_member.model'; -import {GroupService} from '../api-connector/group.service'; -import {ComputecenterComponent} from '../projectmanagement/computecenter.component'; -import {IResponseTemplate} from '../api-connector/response-template'; -import {FacilityService} from '../api-connector/facility.service'; -import {FullLayoutComponent} from '../layouts/full-layout.component'; -import {Application} from '../applications/application.model/application.model'; -import {AbstractBaseClass, Application_States} from '../shared/shared_modules/baseClass/abstract-base-class'; +import { DomSanitizer } from '@angular/platform-browser'; +import { Observable, take } from 'rxjs'; +import { BsModalRef, BsModalService, ModalDirective } from 'ngx-bootstrap/modal'; +import { VoService } from '../api-connector/vo.service'; +import { ProjectMember } from '../projectmanagement/project_member.model'; +import { GroupService } from '../api-connector/group.service'; +import { ComputecenterComponent } from '../projectmanagement/computecenter.component'; +import { IResponseTemplate } from '../api-connector/response-template'; +import { FacilityService } from '../api-connector/facility.service'; +import { FullLayoutComponent } from '../layouts/full-layout.component'; +import { Application } from '../applications/application.model/application.model'; +import { AbstractBaseClass, Application_States } from '../shared/shared_modules/baseClass/abstract-base-class'; import { - NgbdSortableHeaderDirective, - SortEvent, + NgbdSortableHeaderDirective, + SortEvent, } from '../shared/shared_modules/directives/nbd-sortable-header.directive'; -import {ProjectSortService} from '../shared/shared_modules/services/project-sort.service'; -import {StopVmComponent} from '../virtualmachines/modals/stop-vm/stop-vm.component'; -import {BsModalRef, BsModalService} from 'ngx-bootstrap/modal'; -import {ProjectEmailModalComponent} from '../shared/modal/email/project-email-modal/project-email-modal.component'; -import {application} from 'express'; +import { ProjectSortService } from '../shared/shared_modules/services/project-sort.service'; +import { ProjectEmailModalComponent } from '../shared/modal/email/project-email-modal/project-email-modal.component'; /** * Vo Overview component. */ @Component({ - selector: 'app-vo-overview', - templateUrl: 'voOverview.component.html', - providers: [VoService, GroupService, FacilityService, ProjectSortService], + selector: 'app-vo-overview', + templateUrl: 'voOverview.component.html', + providers: [VoService, GroupService, FacilityService, ProjectSortService], }) export class VoOverviewComponent extends AbstractBaseClass implements OnInit { - title: string = 'VO Overview'; - public emailSubject: string; - public emailReply: string = ''; - public emailText: string; - public emailStatus: number = 0; - - public emailHeader: string; - public emailVerify: string; - public emailType: number; - public emailAdminsOnly: boolean = false; - public expiredTemplated: boolean = false; - - public removalDate: Date = new Date(); - public selectedProject: Application; - selectedEmailProjects: Application[] = []; - computecenters: ComputecenterComponent[] = []; - bsModalRef: BsModalRef; - - - show_openstack_projects: boolean = true; - show_simple_vm_projects: boolean = true; - show_simple_vm: boolean = true; - show_openstack: boolean = true; - - selectedProjectType: string = 'ALL'; - selectedFacility: string | number = 'ALL'; - - public newsletterSubscriptionCounter: number; - isLoaded: boolean = false; - member_id: number; - projects: Application[] = []; - projects_filtered: Application[] = []; - - // modal variables for User list - public usersModalProjectMembers: ProjectMember[] = []; - public usersModalProjectID: number; - public usersModalProjectName: string; - public managerFacilities: [string, number][]; - - projectMailTemplates: string[] = [] - @ViewChildren(NgbdSortableHeaderDirective) headers: QueryList; - - applictions$: Observable; - total$: Observable; - - // public selectedFacility: [string, number]; - - constructor( - private fullLayout: FullLayoutComponent, - private sanitizer: DomSanitizer, - private voService: VoService, - private groupservice: GroupService, - private facilityService: FacilityService, - public sortProjectService: ProjectSortService, - private modalService: BsModalService, - ) { - super(); - } - - ngOnInit(): void { - this.getVoProjects(); - this.getComputeCenters(); - this.voService.getNewsletterSubscriptionCounter().subscribe((result: IResponseTemplate): void => { - this.newsletterSubscriptionCounter = result.value as number; - }); - } - - selectAllFilteredProjects(): void { - this.selectedEmailProjects = []; - - // get all the applications - this.applictions$.pipe(take(1)).subscribe(applications => { - // set the selected state of all projects to true - applications.forEach(application => { - application.is_project_selected = true; - this.toggleSelectedEmailApplication(application, application.is_project_selected) - }); - }); - } - - unselectAll(): void { - this.sortProjectService.applications.forEach((pr: Application) => { - pr.is_project_selected = false; - this.toggleSelectedEmailApplication(pr, pr.is_project_selected); - }); - // this.selectedEmailProjects = []; // clear the selectedEmailProjects list - } - - unselectAllFilteredProjects(): void { - // get all the applications - this.applictions$.pipe(take(1)).subscribe(applications => { - // set the selected state of all projects to false - applications.forEach(application => { - application.is_project_selected = false; - this.toggleSelectedEmailApplication(application, application.is_project_selected) - - }); - }); - } - - toggleSelectedEmailApplication(application: Application, isChecked: boolean): void { - const index = this.selectedEmailProjects.indexOf(application); - - if (isChecked) { - // checkbox was checked - if (index === -1) { - // application is not in the list, so add it - this.selectedEmailProjects.push(application); - } + title: string = 'VO Overview'; + public emailSubject: string; + public emailReply: string = ''; + public emailText: string; + public emailStatus: number = 0; + @ViewChild('notificationModal') notificationModal: ModalDirective; + public emailHeader: string; + public emailVerify: string; + public emailType: number; + public emailAdminsOnly: boolean = false; + public expiredTemplated: boolean = false; + + public removalDate: Date = new Date(); + public selectedProject: Application; + selectedEmailProjects: Application[] = []; + computecenters: ComputecenterComponent[] = []; + bsModalRef: BsModalRef; + + show_openstack_projects: boolean = true; + show_simple_vm_projects: boolean = true; + show_simple_vm: boolean = true; + show_openstack: boolean = true; + + selectedProjectType: string = 'ALL'; + selectedFacility: string | number = 'ALL'; + + public newsletterSubscriptionCounter: number; + isLoaded: boolean = false; + member_id: number; + projects: Application[] = []; + projects_filtered: Application[] = []; + + // modal variables for User list + public usersModalProjectMembers: ProjectMember[] = []; + public usersModalProjectID: number; + public usersModalProjectName: string; + public managerFacilities: [string, number][]; + + projectMailTemplates: string[] = []; + @ViewChildren(NgbdSortableHeaderDirective) headers: QueryList; + + applictions$: Observable; + total$: Observable; + + // public selectedFacility: [string, number]; + + constructor( + private fullLayout: FullLayoutComponent, + private sanitizer: DomSanitizer, + private voService: VoService, + private groupservice: GroupService, + private facilityService: FacilityService, + public sortProjectService: ProjectSortService, + private modalService: BsModalService, + ) { + super(); + } + + ngOnInit(): void { + this.getVoProjects(); + this.getComputeCenters(); + this.voService.getNewsletterSubscriptionCounter().subscribe((result: IResponseTemplate): void => { + this.newsletterSubscriptionCounter = result.value as number; + }); + } + + selectAllFilteredProjects(): void { + this.selectedEmailProjects = []; + + // get all the applications + this.applictions$.pipe(take(1)).subscribe(applications => { + // set the selected state of all projects to true + applications.forEach(application => { + application.is_project_selected = true; + this.toggleSelectedEmailApplication(application, application.is_project_selected); + }); + }); + } + + unselectAll(): void { + this.sortProjectService.applications.forEach((pr: Application) => { + pr.is_project_selected = false; + this.toggleSelectedEmailApplication(pr, pr.is_project_selected); + }); + // this.selectedEmailProjects = []; // clear the selectedEmailProjects list + } + + unselectAllFilteredProjects(): void { + // get all the applications + this.applictions$.pipe(take(1)).subscribe(applications => { + // set the selected state of all projects to false + applications.forEach(application => { + application.is_project_selected = false; + this.toggleSelectedEmailApplication(application, application.is_project_selected); + }); + }); + } + + toggleSelectedEmailApplication(application: Application, isChecked: boolean): void { + const index = this.selectedEmailProjects.indexOf(application); + + if (isChecked) { + // checkbox was checked + if (index === -1) { + // application is not in the list, so add it + this.selectedEmailProjects.push(application); + } + } else if (index !== -1) { + // application is in the list, so remove it + this.selectedEmailProjects.splice(index, 1); + } + } + + openProjectMailsModal(): void { + const initialState = { selectedProjects: this.selectedEmailProjects }; + + this.bsModalRef = this.modalService.show(ProjectEmailModalComponent, { initialState, class: 'modal-lg' }); + this.bsModalRef.content.event.subscribe((sent_successfully: boolean) => { + console.log('event recieved'); + console.log(sent_successfully); + if (sent_successfully) { + this.updateNotificationModal('Success', 'Mails were successfully sent', true, 'success'); + } else { + this.updateNotificationModal('Failed', 'Failed to send mails!', true, 'danger'); + } + this.notificationModal.show(); + }); + } + + onSort({ column, direction }: SortEvent) { + // resetting other headers + this.headers.forEach(header => { + if (header.appSortable !== column) { + header.direction = ''; + } + }); + + this.sortProjectService.sortColumn = column; + this.sortProjectService.sortDirection = direction; + } + + getApplicationInfos(): void { + this.voService.getVoProjectResourcesTimeframes().subscribe(); + + this.voService.getVoProjectCounter().subscribe(); + this.voService.getVoProjectDates().subscribe(); + } + + sendEmail(subject: string, message: string, reply?: string): void { + if (reply) { + reply = reply.trim(); + } + switch (this.emailType) { + case 0: { + this.sendMailToVo( + subject, + message, + this.selectedFacility.toString(), + this.selectedProjectType, + this.emailAdminsOnly, + this.expiredTemplated, + this.removalDate, + reply, + ); + break; + } + case 1: { + this.sendNewsletterToVo(subject, message, this.selectedProjectType, this.emailAdminsOnly, reply); + break; + } + default: + } + } + + sendTestBug(): void { + this.voService.sendTestError().subscribe(); + } + + sendNewsletterToVo( + subject: string, + message: string, + selectedProjectType: string, + adminsOnly: boolean, + reply?: string, + ): void { + this.voService + .sendNewsletterToVo( + encodeURIComponent(subject), + encodeURIComponent(message), + selectedProjectType, + adminsOnly, + encodeURIComponent(reply), + ) + .subscribe((result: IResponseTemplate): void => { + if ((result.value as boolean) === true) { + this.emailStatus = 1; } else { - // checkbox was unchecked - if (index !== -1) { - // application is in the list, so remove it - this.selectedEmailProjects.splice(index, 1); - } - } - } - - - openProjectMailsModal(): void { - const initialState = {selectedProjects: this.selectedEmailProjects}; - - this.bsModalRef = this.modalService.show(ProjectEmailModalComponent, {initialState, class: 'modal-lg'}); - } - - - onSort({column, direction}: SortEvent) { - // resetting other headers - this.headers.forEach(header => { - if (header.appSortable !== column) { - header.direction = ''; - } - }); - - this.sortProjectService.sortColumn = column; - this.sortProjectService.sortDirection = direction; - } - - - getApplicationInfos(): void { - this.voService.getVoProjectResourcesTimeframes().subscribe(); - - this.voService.getVoProjectCounter().subscribe(); - this.voService.getVoProjectDates().subscribe(); - } - - sendEmail(subject: string, message: string, reply?: string): void { - if (reply) { - reply = reply.trim(); + this.emailStatus = 2; } - switch (this.emailType) { - case 0: { - this.sendMailToVo( - subject, - message, - this.selectedFacility.toString(), - this.selectedProjectType, - this.emailAdminsOnly, - this.expiredTemplated, - this.removalDate, - reply, - ); - break; - } - case 1: { - this.sendNewsletterToVo(subject, message, this.selectedProjectType, this.emailAdminsOnly, reply); - break; - } - default: + }); + } + + sendMailToVo( + subject: string, + message: string, + facility: string, + type: string, + adminsOnly: boolean, + expiredTemplate: boolean, + removalDate: Date, + reply?: string, + ): void { + this.voService + .sendMailToVo( + encodeURIComponent(subject), + encodeURIComponent(message), + facility, + type, + adminsOnly, + expiredTemplate, + removalDate, + encodeURIComponent(reply), + ) + .subscribe((result: IResponseTemplate): void => { + if ((result.value as boolean) === true) { + this.emailStatus = 1; + } else { + this.emailStatus = 2; } - } - - sendTestBug(): void { - this.voService.sendTestError().subscribe(); - } - - sendNewsletterToVo( - subject: string, - message: string, - selectedProjectType: string, - adminsOnly: boolean, - reply?: string, - ): void { - this.voService - .sendNewsletterToVo( - encodeURIComponent(subject), - encodeURIComponent(message), - selectedProjectType, - adminsOnly, - encodeURIComponent(reply), - ) - .subscribe((result: IResponseTemplate): void => { - if ((result.value as boolean) === true) { - this.emailStatus = 1; - } else { - this.emailStatus = 2; - } - }); - } - - sendMailToVo( - subject: string, - message: string, - facility: string, - type: string, - adminsOnly: boolean, - expiredTemplate: boolean, - removalDate: Date, - reply?: string, - ): void { - this.voService - .sendMailToVo( - encodeURIComponent(subject), - encodeURIComponent(message), - facility, - type, - adminsOnly, - expiredTemplate, - removalDate, - encodeURIComponent(reply), - ) - .subscribe((result: IResponseTemplate): void => { - if ((result.value as boolean) === true) { - this.emailStatus = 1; - } else { - this.emailStatus = 2; - } - this.selectedProjectType = 'ALL'; - this.selectedFacility = 'ALL'; - }); - } - - dayChanged(date: { year: number; month: number; day: number }): void { - this.removalDate.setDate(date.day); - this.removalDate.setMonth(date.month - 1); - this.removalDate.setFullYear(date.year); - } - - setEmailType(type: number): void { - this.emailType = type; - switch (this.emailType) { - case 0: { - this.emailHeader = 'Send email to selected members of the VO'; - break; - } - case 1: { - this.emailHeader = 'Send newsletter to VO'; - break; - } - default: + this.selectedProjectType = 'ALL'; + this.selectedFacility = 'ALL'; + }); + } + + dayChanged(date: { year: number; month: number; day: number }): void { + this.removalDate.setDate(date.day); + this.removalDate.setMonth(date.month - 1); + this.removalDate.setFullYear(date.year); + } + + setEmailType(type: number): void { + this.emailType = type; + switch (this.emailType) { + case 0: { + this.emailHeader = 'Send email to selected members of the VO'; + break; + } + case 1: { + this.emailHeader = 'Send newsletter to VO'; + break; + } + default: + } + this.emailVerify = 'Are you sure you want to send this newsletter to all members of the de.NBI VO?'; + } + + getFacilityName(): string { + if (this.selectedFacility === 'ALL') { + return 'of the de.NBI VO'; + } else { + const temp_cc = this.computecenters.find(cc => cc.FacilityId === this.selectedFacility); + if (temp_cc === undefined) { + return 'of the de.NBI VO'; + } else { + return `of the facility "${temp_cc.Name}"`; + } + } + } + + getMailConfinementByProjectType(): string { + switch (this.selectedProjectType) { + case 'ALL_GM': + return 'of all active projects'; + case 'EXP': + return 'of all expired projects'; + case 'SVP': + return 'of all SimpleVM projects'; + case 'OVP': + return 'of all OpenStack projects'; + case 'WSH': + return 'of all Workshops'; + default: + return ''; + } + } + + adjustVerifyText(): void { + switch (this.emailType) { + case 0: { + this.emailVerify = `Are you sure you want to send this email to all ${ + this.emailAdminsOnly ? ' group administrators' : 'members' + } ${this.getMailConfinementByProjectType()} ${this.getFacilityName()} ?`; + break; + } + case 1: { + this.emailVerify = `Are you sure you want to send this newsletter to all members ${this.getMailConfinementByProjectType()} ${this.getFacilityName()} ?`; + break; + } + default: + this.emailVerify = 'Are you sure you want to send this?'; + } + if (this.selectedProjectType !== 'EXP') { + this.expiredTemplated = false; + } + } + + getVoProjects(): void { + this.projects = []; + this.voService.getAllGroupsWithDetails().subscribe((applications: Application[]): void => { + for (const application of applications) { + if (application.project_application_lifetime > 0) { + application.lifetime_reached = this.lifeTimeReached(application.lifetime_days, application.DaysRunning); } - this.emailVerify = 'Are you sure you want to send this newsletter to all members of the de.NBI VO?'; - } - - getFacilityName(): string { - if (this.selectedFacility === 'ALL') { - return 'of the de.NBI VO'; + this.projects.push(application); + } + this.sortProjectService.applications = this.projects; + this.applictions$ = this.sortProjectService.applications$; + this.total$ = this.sortProjectService.total$; + + this.isLoaded = true; + }); + } + + resetEmailModal(): void { + this.emailHeader = null; + this.emailSubject = null; + this.emailText = null; + this.emailType = null; + this.emailVerify = null; + this.emailReply = ''; + this.emailStatus = 0; + this.emailAdminsOnly = false; + } + + public resetNotificationModal(): void { + this.notificationModalTitle = 'Notification'; + this.notificationModalMessage = 'Please wait...'; + this.notificationModalIsClosable = false; + this.notificationModalType = 'info'; + } + + /** + * Get all computecenters. + */ + getComputeCenters(): void { + this.facilityService.getComputeCenters().subscribe((result: any): void => { + for (const cc of result) { + const compute_center: ComputecenterComponent = new ComputecenterComponent( + cc['compute_center_facility_id'], + cc['compute_center_name'], + cc['compute_center_login'], + cc['compute_center_support_mail'], + ); + this.computecenters.push(compute_center); + } + }); + } + + /** + * Bugfix not scrollable site after closing modal + */ + removeModalOpen(): void { + document.body.classList.remove('modal-open'); + } + + public terminateProject(): void { + this.voService.terminateProject(this.selectedProject.project_application_perun_id).subscribe( + (): void => { + const indexAll: number = this.projects.indexOf(this.selectedProject, 0); + if (!this.selectedProject.project_application_openstack_project) { + this.projects.splice(indexAll, 1); + this.sortProjectService.applications = this.projects; } else { - const temp_cc = this.computecenters.find(cc => cc.FacilityId === this.selectedFacility); - if (temp_cc === undefined) { - return 'of the de.NBI VO'; - } else { - return `of the facility "${temp_cc.Name}"`; - } - } - } - - getMailConfinementByProjectType(): string { - switch (this.selectedProjectType) { - case 'ALL_GM': - return 'of all active projects'; - case 'EXP': - return 'of all expired projects'; - case 'SVP': - return 'of all SimpleVM projects'; - case 'OVP': - return 'of all OpenStack projects'; - case 'WSH': - return 'of all Workshops'; - default: - return ''; + this.getProjectStatus(this.projects[indexAll]); } - } - - adjustVerifyText(): void { - switch (this.emailType) { - case 0: { - this.emailVerify = `Are you sure you want to send this email to all ${ - this.emailAdminsOnly ? ' group administrators' : 'members' - } ${this.getMailConfinementByProjectType()} ${this.getFacilityName()} ?`; - break; - } - case 1: { - this.emailVerify = `Are you sure you want to send this newsletter to all members ${this.getMailConfinementByProjectType()} ${this.getFacilityName()} ?`; - break; - } - default: - this.emailVerify = 'Are you sure you want to send this?'; + this.fullLayout.getGroupsEnumeration(); + if (this.selectedProject.project_application_openstack_project) { + this.updateNotificationModal( + 'Success', + 'The request to terminate the project was forwarded to the facility manager.', + true, + 'success', + ); + } else { + this.updateNotificationModal('Success', 'The project was terminated.', true, 'success'); } - if (this.selectedProjectType !== 'EXP') { - this.expiredTemplated = false; + }, + (error: any): void => { + if (error['status'] === 409) { + this.updateNotificationModal( + 'Failed', + `The project could not be terminated. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, + true, + 'danger', + ); + } else { + this.updateNotificationModal('Failed', 'The project could not be terminated.', true, 'danger'); } - } - - getVoProjects(): void { - this.projects = []; - this.voService.getAllGroupsWithDetails().subscribe((applications: Application[]): void => { - for (const application of applications) { - if (application.project_application_lifetime > 0) { - application.lifetime_reached = this.lifeTimeReached(application.lifetime_days, application.DaysRunning); - } - this.projects.push(application); - } - this.sortProjectService.applications = this.projects; - this.applictions$ = this.sortProjectService.applications$; - this.total$ = this.sortProjectService.total$; - - this.isLoaded = true; - }); - } - - resetEmailModal(): void { - this.emailHeader = null; - this.emailSubject = null; - this.emailText = null; - this.emailType = null; - this.emailVerify = null; - this.emailReply = ''; - this.emailStatus = 0; - this.emailAdminsOnly = false; - } - - public resetNotificationModal(): void { - this.notificationModalTitle = 'Notification'; - this.notificationModalMessage = 'Please wait...'; - this.notificationModalIsClosable = false; - this.notificationModalType = 'info'; - } - - /** - * Get all computecenters. - */ - getComputeCenters(): void { - this.facilityService.getComputeCenters().subscribe((result: any): void => { - for (const cc of result) { - const compute_center: ComputecenterComponent = new ComputecenterComponent( - cc['compute_center_facility_id'], - cc['compute_center_name'], - cc['compute_center_login'], - cc['compute_center_support_mail'], - ); - this.computecenters.push(compute_center); - } - }); - } - - /** - * Bugfix not scrollable site after closing modal - */ - removeModalOpen(): void { - document.body.classList.remove('modal-open'); - } - - public terminateProject(): void { - this.voService.terminateProject(this.selectedProject.project_application_perun_id).subscribe( - (): void => { - const indexAll: number = this.projects.indexOf(this.selectedProject, 0); - if (!this.selectedProject.project_application_openstack_project) { - this.projects.splice(indexAll, 1); - this.sortProjectService.applications = this.projects; - } else { - this.getProjectStatus(this.projects[indexAll]); - } - this.fullLayout.getGroupsEnumeration(); - if (this.selectedProject.project_application_openstack_project) { - this.updateNotificationModal( - 'Success', - 'The request to terminate the project was forwarded to the facility manager.', - true, - 'success', - ); - } else { - this.updateNotificationModal('Success', 'The project was terminated.', true, 'success'); - } - }, - (error: any): void => { - if (error['status'] === 409) { - this.updateNotificationModal( - 'Failed', - `The project could not be terminated. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, - true, - 'danger', - ); - } else { - this.updateNotificationModal('Failed', 'The project could not be terminated.', true, 'danger'); - } - }, - ); - } - - getProjectStatus(project: Application): void { - this.voService.getProjectStatus(project.project_application_perun_id).subscribe((res: any): void => { - project.project_application_statuses = res['status']; - }); - } - - suspendProject(project: Application): void { - this.voService.removeResourceFromGroup(project.project_application_perun_id).subscribe((): void => { - this.getProjectStatus(project); - project.project_application_compute_center = null; - }); - } - - resumeProject(project: Application): void { - this.voService.resumeProject(project.project_application_perun_id).subscribe((): void => { - this.getVoProjects(); - }); - } - - declineTermination(project: Application): void { - this.voService.declineTermination(project.project_application_perun_id).subscribe( - (): void => { - this.updateNotificationModal('Success', 'The termination was successfully declined', true, 'success'); - const indexAll: number = this.projects.indexOf(project, 0); - this.getProjectStatus(this.projects[indexAll]); - }, - (): void => { - this.updateNotificationModal('Failed', 'The status change was not successful.', true, 'danger'); - }, - ); - } - - setProtected(project: Application, set: boolean): void { - this.voService.setProtected(project.project_application_perun_id, set).subscribe( - (result: any): void => { - this.updateNotificationModal( - 'Success', - result['result'] === 'set' - ? 'The project was successfully set as protected.' - : 'The status "Protected" was removed successfully', - true, - 'success', - ); - const indexAll: number = this.projects.indexOf(project, 0); - this.getProjectStatus(this.projects[indexAll]); - }, - (error: any): void => { - if (error['status'] === 500) { - this.updateNotificationModal('Failed', 'The status change was not successful.', true, 'danger'); - } - }, + }, + ); + } + + getProjectStatus(project: Application): void { + this.voService.getProjectStatus(project.project_application_perun_id).subscribe((res: any): void => { + project.project_application_statuses = res['status']; + }); + } + + suspendProject(project: Application): void { + this.voService.removeResourceFromGroup(project.project_application_perun_id).subscribe((): void => { + this.getProjectStatus(project); + project.project_application_compute_center = null; + }); + } + + resumeProject(project: Application): void { + this.voService.resumeProject(project.project_application_perun_id).subscribe((): void => { + this.getVoProjects(); + }); + } + + declineTermination(project: Application): void { + this.voService.declineTermination(project.project_application_perun_id).subscribe( + (): void => { + this.updateNotificationModal('Success', 'The termination was successfully declined', true, 'success'); + const indexAll: number = this.projects.indexOf(project, 0); + this.getProjectStatus(this.projects[indexAll]); + }, + (): void => { + this.updateNotificationModal('Failed', 'The status change was not successful.', true, 'danger'); + }, + ); + } + + setProtected(project: Application, set: boolean): void { + this.voService.setProtected(project.project_application_perun_id, set).subscribe( + (result: any): void => { + this.updateNotificationModal( + 'Success', + result['result'] === 'set' + ? 'The project was successfully set as protected.' + : 'The status "Protected" was removed successfully', + true, + 'success', ); - } - - getMembersOfTheProject(projectid: number, projectname: string): void { - this.voService.getVoGroupRichMembers(projectid).subscribe((members: ProjectMember[]): void => { - this.usersModalProjectID = projectid; - this.usersModalProjectName = projectname; - this.usersModalProjectMembers = members; - }); - } - - showMembersOfTheProject(projectid: number, projectname: string): void { - this.getMembersOfTheProject(projectid, projectname); - } - - exportTSV(): void { - const data = []; - this.sortProjectService.sorted_applications.forEach(application => { - const entry = {}; - for (const key in application) { - if (typeof application[key] === 'object') { - if (key === 'project_application_pi') { - entry['project_application_pi_name'] = application[key].username; - entry['project_application_pi_email'] = application[key].email; - entry['project_application_pi_affiliations'] = JSON.stringify(application[key].user_affiliations); - } else if (key === 'project_application_statuses') { - const statuses_strings = []; - application[key].forEach(status => { - statuses_strings.push(Application_States[status]); - }); - entry[key] = JSON.stringify(statuses_strings); - } else if (key === 'project_credit_request') { - if (application[key] == null) { - entry['project_credit_requested'] = 'FALSE'; - entry['project_credit_request_id'] = 'NONE'; - entry['project_credit_request_comment'] = 'NONE'; - entry['project_credit_request_date_submitted'] = 'NONE'; - entry['project_credit_request_extra_credits'] = 'NONE'; - entry['project_credit_request_user_name'] = 'NONE'; - entry['project_credit_request_user_email'] = 'NONE'; - } else { - entry['project_credit_requested'] = 'TRUE'; - entry['project_credit_request_id'] = JSON.stringify(application[key].Id); - entry['project_credit_request_comment'] = application[key].comment; - entry['project_credit_request_date_submitted'] = JSON.stringify(application[key].date_submitted); - entry['project_credit_request_extra_credits'] = JSON.stringify(application[key].extra_credits); - entry['project_credit_request_user_name'] = JSON.stringify(application[key].user.username); - entry['project_credit_request_user_email'] = JSON.stringify(application[key].user.email); - } - } else if (key === 'project_application_edam_terms') { - const edam_names = []; - application[key].forEach(edam => { - edam_names.push(edam.name); - }); - entry['project_application_edam_terms'] = JSON.stringify(edam_names); - } else if (key === 'flavors') { - const flavor_names = []; - application[key].forEach(flavor => { - flavor_names.push(flavor.name); - }); - } else if (key === 'dissemination') { - /* empty */ - } else if (key === 'project_application_compute_center') { - entry[key] = application[key].Name; - entry['project_application_compute_center_id'] = application[key].FacilityId; - } else { - entry[key] = JSON.stringify(application[key]); - } - } else { - entry[key] = application[key]; - } + const indexAll: number = this.projects.indexOf(project, 0); + this.getProjectStatus(this.projects[indexAll]); + }, + (error: any): void => { + if (error['status'] === 500) { + this.updateNotificationModal('Failed', 'The status change was not successful.', true, 'danger'); + } + }, + ); + } + + getMembersOfTheProject(projectid: number, projectname: string): void { + this.voService.getVoGroupRichMembers(projectid).subscribe((members: ProjectMember[]): void => { + this.usersModalProjectID = projectid; + this.usersModalProjectName = projectname; + this.usersModalProjectMembers = members; + }); + } + + showMembersOfTheProject(projectid: number, projectname: string): void { + this.getMembersOfTheProject(projectid, projectname); + } + + exportTSV(): void { + const data = []; + this.sortProjectService.sorted_applications.forEach(application => { + const entry = {}; + for (const key in application) { + if (typeof application[key] === 'object') { + if (key === 'project_application_pi') { + entry['project_application_pi_name'] = application[key].username; + entry['project_application_pi_email'] = application[key].email; + entry['project_application_pi_affiliations'] = JSON.stringify(application[key].user_affiliations); + } else if (key === 'project_application_statuses') { + const statuses_strings = []; + application[key].forEach(status => { + statuses_strings.push(Application_States[status]); + }); + entry[key] = JSON.stringify(statuses_strings); + } else if (key === 'project_credit_request') { + if (application[key] == null) { + entry['project_credit_requested'] = 'FALSE'; + entry['project_credit_request_id'] = 'NONE'; + entry['project_credit_request_comment'] = 'NONE'; + entry['project_credit_request_date_submitted'] = 'NONE'; + entry['project_credit_request_extra_credits'] = 'NONE'; + entry['project_credit_request_user_name'] = 'NONE'; + entry['project_credit_request_user_email'] = 'NONE'; + } else { + entry['project_credit_requested'] = 'TRUE'; + entry['project_credit_request_id'] = JSON.stringify(application[key].Id); + entry['project_credit_request_comment'] = application[key].comment; + entry['project_credit_request_date_submitted'] = JSON.stringify(application[key].date_submitted); + entry['project_credit_request_extra_credits'] = JSON.stringify(application[key].extra_credits); + entry['project_credit_request_user_name'] = JSON.stringify(application[key].user.username); + entry['project_credit_request_user_email'] = JSON.stringify(application[key].user.email); } - data.push(entry); - }); - if (data.length > 0) { - // create CSV file first for convenience - const currentDate = new Date().toISOString().split('T')[0]; - // eslint-disable-next-line - const csv = new ngxCsv(data, 'cloud_projects_' + currentDate, { - showLabels: true, - headers: Object.keys(data[0]), - fieldSeparator: '\t', - noDownload: true, + } else if (key === 'project_application_edam_terms') { + const edam_names = []; + application[key].forEach(edam => { + edam_names.push(edam.name); }); - // create TSV file and download it - const link = document.createElement('a'); - link.href = `data:text/tab-separated-values,${encodeURIComponent(csv.getCsv())}`; - link.download = `cloud_projects_${currentDate}.tsv`; - link.click(); + entry['project_application_edam_terms'] = JSON.stringify(edam_names); + } else if (key === 'flavors') { + const flavor_names = []; + application[key].forEach(flavor => { + flavor_names.push(flavor.name); + }); + } else if (key === 'dissemination') { + /* empty */ + } else if (key === 'project_application_compute_center') { + entry[key] = application[key].Name; + entry['project_application_compute_center_id'] = application[key].FacilityId; + } else { + entry[key] = JSON.stringify(application[key]); + } + } else { + entry[key] = application[key]; } - } + } + data.push(entry); + }); + if (data.length > 0) { + // create CSV file first for convenience + const currentDate = new Date().toISOString().split('T')[0]; + // eslint-disable-next-line + const csv = new ngxCsv(data, 'cloud_projects_' + currentDate, { + showLabels: true, + headers: Object.keys(data[0]), + fieldSeparator: '\t', + noDownload: true, + }); + // create TSV file and download it + const link = document.createElement('a'); + link.href = `data:text/tab-separated-values,${encodeURIComponent(csv.getCsv())}`; + link.download = `cloud_projects_${currentDate}.tsv`; + link.click(); + } + } }