From 791903a80d67aa2af61ecc15fc42ee37c48b7efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 6 Feb 2024 15:43:18 +0100 Subject: [PATCH] MOBILE-4329 dataprivacy: Implement data privacy pages --- scripts/langindex.json | 34 ++++ src/core/components/empty-box/empty-box.scss | 2 +- .../components/components.module.ts | 33 ++++ .../components/contactdpo/contactdpo.html | 37 ++++ .../components/contactdpo/contactdpo.ts | 94 ++++++++++ .../components/newrequest/newrequest.html | 50 ++++++ .../components/newrequest/newrequest.ts | 104 +++++++++++ .../dataprivacy/dataprivacy-lazy.module.ts | 38 ++++ .../dataprivacy/dataprivacy.module.ts | 14 ++ src/core/features/dataprivacy/lang.json | 35 +++- .../features/dataprivacy/pages/main/main.html | 160 +++++++++++++++++ .../features/dataprivacy/pages/main/main.scss | 10 ++ .../features/dataprivacy/pages/main/main.ts | 167 ++++++++++++++++++ .../dataprivacy/services/dataprivacy.ts | 4 +- src/core/features/editor/editor.module.ts | 2 - 15 files changed, 778 insertions(+), 6 deletions(-) create mode 100644 src/core/features/dataprivacy/components/components.module.ts create mode 100644 src/core/features/dataprivacy/components/contactdpo/contactdpo.html create mode 100644 src/core/features/dataprivacy/components/contactdpo/contactdpo.ts create mode 100644 src/core/features/dataprivacy/components/newrequest/newrequest.html create mode 100644 src/core/features/dataprivacy/components/newrequest/newrequest.ts create mode 100644 src/core/features/dataprivacy/dataprivacy-lazy.module.ts create mode 100644 src/core/features/dataprivacy/pages/main/main.html create mode 100644 src/core/features/dataprivacy/pages/main/main.scss create mode 100644 src/core/features/dataprivacy/pages/main/main.ts diff --git a/scripts/langindex.json b/scripts/langindex.json index 7c05d22da..d5de79409 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1677,6 +1677,40 @@ "core.courses.totalcoursesearchresults": "local_moodlemobileapp", "core.currentdevice": "local_moodlemobileapp", "core.custom": "form", + "core.dataprivacy.cancelrequest": "tool_dataprivacy", + "core.dataprivacy.cancelrequestconfirmation": "tool_dataprivacy", + "core.dataprivacy.contactdataprotectionofficer": "tool_dataprivacy", + "core.dataprivacy.createnewdatarequest": "tool_dataprivacy", + "core.dataprivacy.datarequests": "tool_dataprivacy", + "core.dataprivacy.daterequested": "tool_dataprivacy", + "core.dataprivacy.deletemyaccount": "tool_dataprivacy", + "core.dataprivacy.message": "tool_dataprivacy", + "core.dataprivacy.newrequest": "tool_dataprivacy", + "core.dataprivacy.nodatarequests": "tool_dataprivacy", + "core.dataprivacy.pluginname": "tool_dataprivacy", + "core.dataprivacy.replyto": "tool_dataprivacy", + "core.dataprivacy.requestactions": "tool_dataprivacy", + "core.dataprivacy.requestby": "tool_dataprivacy", + "core.dataprivacy.requestcomments": "tool_dataprivacy", + "core.dataprivacy.requeststatus": "tool_dataprivacy", + "core.dataprivacy.requestsubmitted": "tool_dataprivacy", + "core.dataprivacy.requesttype": "tool_dataprivacy", + "core.dataprivacy.requesttype_help": "tool_dataprivacy", + "core.dataprivacy.requesttypedelete": "tool_dataprivacy", + "core.dataprivacy.requesttypeexport": "tool_dataprivacy", + "core.dataprivacy.requesttypeothers": "tool_dataprivacy", + "core.dataprivacy.send": "tool_dataprivacy", + "core.dataprivacy.statusapproved": "tool_dataprivacy", + "core.dataprivacy.statusawaitingapproval": "tool_dataprivacy", + "core.dataprivacy.statuscancelled": "tool_dataprivacy", + "core.dataprivacy.statuscomplete": "tool_dataprivacy", + "core.dataprivacy.statusdeleted": "tool_dataprivacy", + "core.dataprivacy.statusexpired": "tool_dataprivacy", + "core.dataprivacy.statuspending": "tool_dataprivacy", + "core.dataprivacy.statuspreprocessing": "tool_dataprivacy", + "core.dataprivacy.statusprocessing": "tool_dataprivacy", + "core.dataprivacy.statusready": "tool_dataprivacy", + "core.dataprivacy.statusrejected": "tool_dataprivacy", "core.datastoredoffline": "local_moodlemobileapp", "core.date": "moodle", "core.datecreated": "repository", diff --git a/src/core/components/empty-box/empty-box.scss b/src/core/components/empty-box/empty-box.scss index 7c57385ea..db3208472 100644 --- a/src/core/components/empty-box/empty-box.scss +++ b/src/core/components/empty-box/empty-box.scss @@ -2,7 +2,7 @@ :host { --image-size: 120px; - --icon-color: var(--text-color); + --icon-color: var(--subdued-text-color); display: flex; flex-direction: column; diff --git a/src/core/features/dataprivacy/components/components.module.ts b/src/core/features/dataprivacy/components/components.module.ts new file mode 100644 index 000000000..9b857a50a --- /dev/null +++ b/src/core/features/dataprivacy/components/components.module.ts @@ -0,0 +1,33 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CoreSharedModule } from '@/core/shared.module'; +import { CoreDataPrivacyContactDPOComponent } from './contactdpo/contactdpo'; +import { CoreDataPrivacyNewRequestComponent } from './newrequest/newrequest'; + +@NgModule({ + declarations: [ + CoreDataPrivacyContactDPOComponent, + CoreDataPrivacyNewRequestComponent, + ], + imports: [ + CoreSharedModule, + ], + exports: [ + CoreDataPrivacyContactDPOComponent, + CoreDataPrivacyNewRequestComponent, + ], +}) +export class CoreDataPrivacyComponentsModule {} diff --git a/src/core/features/dataprivacy/components/contactdpo/contactdpo.html b/src/core/features/dataprivacy/components/contactdpo/contactdpo.html new file mode 100644 index 000000000..9192b9051 --- /dev/null +++ b/src/core/features/dataprivacy/components/contactdpo/contactdpo.html @@ -0,0 +1,37 @@ + + + +

{{ 'core.dataprivacy.contactdataprotectionofficer' | translate }}

+
+ + + + +
+
+ +
+ + +

+ {{ 'core.dataprivacy.replyto' | translate }} +

+

{{ email }}

+
+
+ + +
+ {{ 'core.dataprivacy.message' | translate }} +
+
+
+
+
+ + + {{ 'core.dataprivacy.send' | translate }} + + diff --git a/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts b/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts new file mode 100644 index 000000000..2e531b444 --- /dev/null +++ b/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts @@ -0,0 +1,94 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { CoreDataPrivacy } from '@features/dataprivacy/services/dataprivacy'; +import { CoreUser } from '@features/user/services/user'; +import { CoreSites } from '@services/sites'; +import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; + +import { ModalController } from '@singletons'; + +/** + * Component that displays the contact DPO page. + */ +@Component({ + selector: 'core-data-privacy-contact-dpo', + templateUrl: 'contactdpo.html', +}) +export class CoreDataPrivacyContactDPOComponent implements OnInit { + + message = ''; + email = ''; + + // Form variables. + form: FormGroup; + + constructor( + protected fb: FormBuilder, + ) { + this.form = new FormGroup({}); + + // Initialize form variables. + this.form.addControl('message', this.fb.control('', Validators.required)); + } + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + const modal = await CoreDomUtils.showModalLoading(); + + // Get current user email. + const userId = CoreSites.getCurrentSiteUserId(); + const user = await CoreUtils.ignoreErrors(CoreUser.getProfile(userId)); + + this.email = user?.email || ''; + + modal.dismiss(); + } + + /** + * Sends the message. + */ + async send(event: Event): Promise { + event.preventDefault(); + event.stopPropagation(); + + const modal = await CoreDomUtils.showModalLoading(); + + try { + // Send the message. + const succeed = await CoreDataPrivacy.contactDPO(this.message); + if (succeed) { + CoreDomUtils.showToast('core.dataprivacy.requestsubmitted', true, ToastDuration.LONG); + ModalController.dismiss(true); + } + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'Error sending data privacy request'); + } finally { + modal.dismiss(); + } + } + + /** + * Close modal. + */ + close(): void { + ModalController.dismiss(); + } + +} diff --git a/src/core/features/dataprivacy/components/newrequest/newrequest.html b/src/core/features/dataprivacy/components/newrequest/newrequest.html new file mode 100644 index 000000000..8b2ee4076 --- /dev/null +++ b/src/core/features/dataprivacy/components/newrequest/newrequest.html @@ -0,0 +1,50 @@ + + + +

{{ 'core.dataprivacy.createnewdatarequest' | translate }}

+
+ + + + +
+
+ +
+ + +

+ {{ 'core.dataprivacy.requesttype_help' | translate }} +

+

+ {{ 'core.dataprivacy.requesttype' | translate }} +

+
+
+ + + + {{ 'core.dataprivacy.requesttypeexport' | translate }} + + + {{ 'core.dataprivacy.requesttypedelete' | translate }} + + + + + +
+ {{ 'core.dataprivacy.requestcomments' | translate }} +
+
+
+ +
+
+ + + {{ 'core.dataprivacy.send' | translate }} + + diff --git a/src/core/features/dataprivacy/components/newrequest/newrequest.ts b/src/core/features/dataprivacy/components/newrequest/newrequest.ts new file mode 100644 index 000000000..7e75e4e6b --- /dev/null +++ b/src/core/features/dataprivacy/components/newrequest/newrequest.ts @@ -0,0 +1,104 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { + CoreDataPrivacy, + CoreDataPrivacyDataRequestType, + CoreDataPrivacyGetAccessInformationWSResponse, +} from '@features/dataprivacy/services/dataprivacy'; +import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; + +import { ModalController } from '@singletons'; + +/** + * Component that displays the new request page. + */ +@Component({ + selector: 'core-data-privacy-new-request', + templateUrl: 'newrequest.html', +}) +export class CoreDataPrivacyNewRequestComponent implements OnInit { + + @Input() accessInfo?: CoreDataPrivacyGetAccessInformationWSResponse; + + message = ''; + + // Form variables. + form: FormGroup; + typeControl: FormControl; + + constructor( + protected fb: FormBuilder, + ) { + this.form = new FormGroup({}); + + // Initialize form variables. + this.typeControl = this.fb.control( + CoreDataPrivacyDataRequestType.DATAREQUEST_TYPE_EXPORT, + { validators: Validators.required, nonNullable: true }, + ); + this.form.addControl('type', this.typeControl); + this.form.addControl('message', this.fb.control('')); + } + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + // It should not happen. If there's no access info, close the modal. + if (!this.accessInfo) { + ModalController.dismiss(); + + return; + } + + // Just in case only deleting is allowed, change the default type. + if (!this.accessInfo.cancreatedatadownloadrequest && this.accessInfo.cancreatedatadeletionrequest){ + this.typeControl.setValue(CoreDataPrivacyDataRequestType.DATAREQUEST_TYPE_DELETE); + } + } + + /** + * Sends the request. + */ + async send(event: Event): Promise { + event.preventDefault(); + event.stopPropagation(); + + const modal = await CoreDomUtils.showModalLoading(); + + try { + // Send the message. + const requestId = await CoreDataPrivacy.createDataRequest(this.typeControl.value, this.message); + if (requestId) { + CoreDomUtils.showToast('core.dataprivacy.requestsubmitted', true, ToastDuration.LONG); + ModalController.dismiss(true); + } + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'Error sending data privacy request'); + } finally { + modal.dismiss(); + } + } + + /** + * Close modal. + */ + close(): void { + ModalController.dismiss(); + } + +} diff --git a/src/core/features/dataprivacy/dataprivacy-lazy.module.ts b/src/core/features/dataprivacy/dataprivacy-lazy.module.ts new file mode 100644 index 000000000..b0431a131 --- /dev/null +++ b/src/core/features/dataprivacy/dataprivacy-lazy.module.ts @@ -0,0 +1,38 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CoreSharedModule } from '@/core/shared.module'; +import { CoreDataPrivacyMainPage } from './pages/main/main'; + +const routes: Routes = [ + { + path: '', + pathMatch: 'full', + component: CoreDataPrivacyMainPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreSharedModule, + ], + declarations: [ + CoreDataPrivacyMainPage, + ], +}) +export class CoreDataPrivacyLazyModule {} diff --git a/src/core/features/dataprivacy/dataprivacy.module.ts b/src/core/features/dataprivacy/dataprivacy.module.ts index 886e212a4..6891562d4 100644 --- a/src/core/features/dataprivacy/dataprivacy.module.ts +++ b/src/core/features/dataprivacy/dataprivacy.module.ts @@ -15,9 +15,23 @@ import { APP_INITIALIZER, NgModule } from '@angular/core'; import { CoreUserDelegate } from '@features/user/services/user-delegate'; import { CoreDataPrivacyUserHandler } from './services/handlers/user'; +import { Routes } from '@angular/router'; +import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module'; +import { CoreDataPrivacyComponentsModule } from './components/components.module'; +import { CORE_DATAPRIVACY_PAGE_NAME } from './constants'; +const routes: Routes = [ + { + path: CORE_DATAPRIVACY_PAGE_NAME, + loadChildren: () => import('./dataprivacy-lazy.module').then(m => m.CoreDataPrivacyLazyModule), + }, +]; @NgModule({ + imports: [ + CoreMainMenuTabRoutingModule.forChild(routes), + CoreDataPrivacyComponentsModule, + ], providers: [ { provide: APP_INITIALIZER, diff --git a/src/core/features/dataprivacy/lang.json b/src/core/features/dataprivacy/lang.json index 6e1a74f55..13f0290bd 100644 --- a/src/core/features/dataprivacy/lang.json +++ b/src/core/features/dataprivacy/lang.json @@ -1,3 +1,36 @@ { - "pluginname": "Data privacy" + "contactdataprotectionofficer": "Contact the privacy officer", + "cancelrequest": "Cancel request", + "cancelrequestconfirmation": "Do you really want cancel this data request?", + "createnewdatarequest": "Create a new data request", + "datarequests": "Data requests", + "daterequested": "Date requested", + "deletemyaccount": "Delete my account", + "message": "Message", + "newrequest": "New request", + "nodatarequests": "There are no data requests", + "pluginname": "Data privacy", + "replyto": "Reply to", + "requestactions": "Actions", + "requestby": "Requested by", + "requestcomments": "Comments", + "requeststatus": "Status", + "requestsubmitted": "Your request has been submitted to the privacy officer", + "requesttype_help": "Select the reason for contacting the privacy officer. Be aware that deletion of all personal data will result in you no longer being able to log in to the site.", + "requesttype": "Type", + "requesttypedelete": "Delete all of my personal data", + "requesttypeexport": "Export all of my personal data", + "requesttypeothers": "General enquiry", + "send": "Send", + "statusapproved": "Approved", + "statusawaitingapproval": "Awaiting approval", + "statuscancelled": "Cancelled", + "statuscomplete": "Complete", + "statusdeleted": "Deleted", + "statusexpired": "Expired", + "statuspending": "Pending", + "statuspreprocessing": "Pre-processing", + "statusprocessing": "Processing", + "statusready": "Download ready", + "statusrejected": "Rejected" } diff --git a/src/core/features/dataprivacy/pages/main/main.html b/src/core/features/dataprivacy/pages/main/main.html new file mode 100644 index 000000000..5e42746b8 --- /dev/null +++ b/src/core/features/dataprivacy/pages/main/main.html @@ -0,0 +1,160 @@ + + + + + + +

{{ 'core.dataprivacy.pluginname' | translate }}

+
+
+
+ + + + + + + +

{{ 'core.dataprivacy.datarequests' | translate }}

+
+
+ + + + +

+ +

+ + +

{{request.timecreated * 1000 | coreFormatDate }}

+
+ + + +
+
+
+ + +

{{ 'core.dataprivacy.requestby' | translate }}

+

{{ request.requestedbyuser.fullname }}

+
+
+ + +

{{ 'core.dataprivacy.message' | translate }}

+

+
+
+ + + + {{ 'core.dataprivacy.cancelrequest' | translate }} + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
{{ 'core.dataprivacy.requesttype' | translate }}{{ 'core.dataprivacy.daterequested' | translate }}{{ 'core.dataprivacy.requestby' | translate }}{{ 'core.dataprivacy.requeststatus' | translate }}{{ 'core.dataprivacy.message' | translate }}{{ 'core.dataprivacy.requestactions' | translate }}
+

+
+

{{request.timecreated * 1000 | coreFormatDate }}

+
+

{{ request.requestedbyuser.fullname }}

+
+ + +

+
+ + {{ 'core.dataprivacy.cancelrequest' | translate }} + +
+ + + +
+
+ + + {{ 'core.dataprivacy.contactdataprotectionofficer' | translate }} + + + + {{ 'core.dataprivacy.newrequest' | translate }} + +
+
+ +
+
+ + + @switch (request.status) { + @case (0) { + {{'core.dataprivacy.statuspending' | translate }} + } @case (1) { + {{'core.dataprivacy.statuspreprocessing' | translate }} + } @case (2) { + {{'core.dataprivacy.statusawaitingapproval' | translate }} + } @case (3) { + {{'core.dataprivacy.statusapproved' | translate }} + } @case (4) { + {{'core.dataprivacy.statusprocessing' | translate }} + } @case (5) { + {{'core.dataprivacy.statuscomplete' | translate }} + } @case (6) { + {{'core.dataprivacy.statuscancelled' | translate }} + } @case (7) { + {{'core.dataprivacy.statusrejected' | translate }} + } @case (8) { + {{'core.dataprivacy.statusready' | translate }} + } @case (9) { + {{'core.dataprivacy.statusexpired' | translate }} + } @case (10) { + {{'core.dataprivacy.statusdeleted' | translate }} + } @default { + {{request.statuslabel}} + } + } + + + + @switch (request.type) { + @case (1) { + {{ 'core.dataprivacy.requesttypeexport' | translate }} + } @case (2) { + {{ 'core.dataprivacy.requesttypedelete' | translate }} + } @case (3) { + {{ 'core.dataprivacy.requesttypeothers' | translate }} + } @default { + {{request.typename}} + } + } + diff --git a/src/core/features/dataprivacy/pages/main/main.scss b/src/core/features/dataprivacy/pages/main/main.scss new file mode 100644 index 000000000..b5e585f20 --- /dev/null +++ b/src/core/features/dataprivacy/pages/main/main.scss @@ -0,0 +1,10 @@ + +table { + th { + width: 20%; + } + + th.shrink { + width: 1%; + } +} diff --git a/src/core/features/dataprivacy/pages/main/main.ts b/src/core/features/dataprivacy/pages/main/main.ts new file mode 100644 index 000000000..dfbc8a23f --- /dev/null +++ b/src/core/features/dataprivacy/pages/main/main.ts @@ -0,0 +1,167 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { CoreDataPrivacyContactDPOComponent } from '@features/dataprivacy/components/contactdpo/contactdpo'; +import { CoreDataPrivacyNewRequestComponent } from '@features/dataprivacy/components/newrequest/newrequest'; +import { + CoreDataPrivacy, + CoreDataPrivacyGetAccessInformationWSResponse, + CoreDataPrivacyRequest, +} from '@features/dataprivacy/services/dataprivacy'; +import { CoreScreen } from '@services/screen'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; +import { Translate } from '@singletons'; +import { Subscription } from 'rxjs'; + +/** + * Page to display the main data privacy page. + */ +@Component({ + selector: 'page-core-data-privacy-main', + templateUrl: 'main.html', + styleUrl: 'main.scss', +}) +export class CoreDataPrivacyMainPage implements OnInit { + + accessInfo?: CoreDataPrivacyGetAccessInformationWSResponse; + requests: CoreDataPrivacyRequestToDisplay[] = []; + loaded = false; + isTablet = false; + layoutSubscription?: Subscription; + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + this.fetchContent(); + + this.isTablet = CoreScreen.isTablet; + + this.layoutSubscription = CoreScreen.layoutObservable.subscribe(() => { + this.isTablet = CoreScreen.isTablet; + }); + } + + /** + * Fetch page content. + */ + async fetchContent(): Promise { + try { + this.accessInfo = await CoreDataPrivacy.getAccessInformation(); + + this.requests = await CoreDataPrivacy.getDataRequests(); + + this.requests.forEach((request) => { + request.canCancel = CoreDataPrivacy.canCancelRequest(request); + }); + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'Error fetching data privacy information', true); + } finally { + this.loaded = true; + } + } + + /** + * Refresh the page content. + * + * @param refresher Refresher. + */ + async refreshContent(refresher?: HTMLIonRefresherElement): Promise { + await CoreUtils.ignoreErrors( + CoreDataPrivacy.invalidateAll(), + ); + + await CoreUtils.ignoreErrors(this.fetchContent()); + + refresher?.complete(); + } + + /** + * Open the contact DPO modal. + */ + async contactDPO(): Promise { + // Create and show the modal. + const succeed = await CoreDomUtils.openModal({ + component: CoreDataPrivacyContactDPOComponent, + }); + + if (succeed) { + const modal = await CoreDomUtils.showModalLoading(); + try { + await this.refreshContent(); + } finally { + modal.dismiss(); + } + } + } + + /** + * Open the new request modal. + */ + async newRequest(): Promise { + // Create and show the modal. + const succeed = await CoreDomUtils.openModal({ + component: CoreDataPrivacyNewRequestComponent, + componentProps: { + accessInfo: this.accessInfo, + }, + }); + + if (succeed) { + const modal = await CoreDomUtils.showModalLoading(); + try { + await this.refreshContent(); + } finally { + modal.dismiss(); + } + } + } + + /** + * Cancel a request. + * + * @param requestId Request ID. + */ + async cancelRequest(requestId: number): Promise { + + try { + await CoreDomUtils.showConfirm( + Translate.instant('core.dataprivacy.cancelrequestconfirmation'), + Translate.instant('core.dataprivacy.cancelrequest'), + Translate.instant('core.dataprivacy.cancelrequest'), + ); + } catch { + return; + } + + const modal = await CoreDomUtils.showModalLoading(); + + try { + await CoreDataPrivacy.cancelDataRequest(requestId); + + await this.refreshContent(); + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'Error cancelling data privacy request'); + } finally { + modal.dismiss(); + } + } + +} + +type CoreDataPrivacyRequestToDisplay = CoreDataPrivacyRequest & { + canCancel?: boolean; +}; diff --git a/src/core/features/dataprivacy/services/dataprivacy.ts b/src/core/features/dataprivacy/services/dataprivacy.ts index 00e158392..21feed9c6 100644 --- a/src/core/features/dataprivacy/services/dataprivacy.ts +++ b/src/core/features/dataprivacy/services/dataprivacy.ts @@ -170,7 +170,7 @@ export class CoreDataPrivacyService { async createDataRequest(type: CoreDataPrivacyDataRequestType, comments: string, siteId?: string): Promise { const site = await CoreSites.getSite(siteId); - const params: CoreDataPrivacyCreateDataequestWSParams = { + const params: CoreDataPrivacyCreateDataRequestWSParams = { type, comments, }; @@ -292,7 +292,7 @@ type CoreDataPrivacyContactDPOWSResponse = { /** * Params of tool_dataprivacy_create_data_request WS. */ -type CoreDataPrivacyCreateDataequestWSParams = { +type CoreDataPrivacyCreateDataRequestWSParams = { type: CoreDataPrivacyDataRequestType; // The type of data request to create. 1 for export, 2 for data deletion. comments?: string; // Comments for the data request. foruserid?: number; // The id of the user to create the data request for. Empty for current user. diff --git a/src/core/features/editor/editor.module.ts b/src/core/features/editor/editor.module.ts index 49cf85887..d179f925f 100644 --- a/src/core/features/editor/editor.module.ts +++ b/src/core/features/editor/editor.module.ts @@ -24,8 +24,6 @@ export const CORE_EDITOR_SERVICES: Type[] = [ ]; @NgModule({ - declarations: [ - ], imports: [ CoreEditorComponentsModule, ],