Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Consent manager issues in CDS TK #27

Merged
merged 20 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b5ca2c4
Update revoked consent details in UI after revoking
anjuchamantha Oct 22, 2024
d69e238
Remove useless link in consentmgr footer
anjuchamantha Oct 22, 2024
77f1cc2
Fix consent confirmation pdf file issues
anjuchamantha Oct 25, 2024
bc9ac5d
Fix consentmgr ADR logo not showing issue
anjuchamantha Oct 25, 2024
c76c093
Fix consentmgr accredation typo
anjuchamantha Oct 25, 2024
e5817f1
Get sharing duration for onceOff consents in consent manager
anjuchamantha Oct 25, 2024
377316a
Refactor date titles for consent manager consents
anjuchamantha Oct 25, 2024
1a94ee4
Fix Customer Care Officer not able to revoke the consent issue
anjuchamantha Oct 28, 2024
7feaaee
Allowing CustomerCareOfficer to view consent amendment history
anjuchamantha Oct 31, 2024
5d38d86
Revoke consent if all the mappings are deactivated
anjuchamantha Nov 4, 2024
c68d45b
Show consent amendment history details to customer care officer
anjuchamantha Nov 7, 2024
8dfced3
Send correct consent amended time
anjuchamantha Nov 7, 2024
6fcc5a4
Merge branch 'main' into consent-mgr-issues
anjuchamantha Nov 11, 2024
32c32e1
Code refactoring in consent manager consent pdf generation
anjuchamantha Nov 11, 2024
ca7d479
Change consent `revoked` status to `Revoked`
anjuchamantha Nov 11, 2024
db666b9
Fix consent manager pdf key date issues
anjuchamantha Nov 11, 2024
44eff1d
Show accounts in consent pdf only if accounts are there
anjuchamantha Nov 11, 2024
49af6e9
Merge branch 'main' into consent-mgr-issues
anjuchamantha Nov 18, 2024
8a8b7f0
Bug fix in consent manager pdf generation
anjuchamantha Nov 19, 2024
eaaa2e7
Merge branch 'main' into consent-mgr-issues
anjuchamantha Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,6 @@ public void handleConsentAmendmentHistoryRetrieval(ConsentAdminData consentAdmin
"not available");
}

if (StringUtils.isBlank(userID)) {
log.error("Request missing the mandatory query parameter userID");
throw new ConsentException(ResponseStatus.BAD_REQUEST, "Mandatory query parameter userID " +
"not available");
}

int count, amendmentCount = 0;

try {
Expand All @@ -178,7 +172,8 @@ public void handleConsentAmendmentHistoryRetrieval(ConsentAdminData consentAdmin

DetailedConsentResource currentConsentResource = this.consentCoreService.getDetailedConsent(consentID);

if (isActionByPrimaryUser(currentConsentResource, userID)) {
// userID is null when the request comes from a user with CustomerCareOfficer role in consent manager.
if (userID == null || isActionByPrimaryUser(currentConsentResource, userID)) {

JSONArray consentHistory = new JSONArray();
for (Map.Entry<String, ConsentHistoryResource> result : results.entrySet()) {
Expand All @@ -188,7 +183,7 @@ public void handleConsentAmendmentHistoryRetrieval(ConsentAdminData consentAdmin
consentHistoryResource.getDetailedConsentResource();
consentResourceJSON.appendField("historyId", result.getKey());
consentResourceJSON.appendField("amendedReason", consentHistoryResource.getReason());
consentResourceJSON.appendField("amendedTime", detailedConsentResource.getUpdatedTime());
consentResourceJSON.appendField("amendedTime", consentHistoryResource.getTimestamp());
consentResourceJSON.appendField("previousConsentData",
this.detailedConsentToJSON(detailedConsentResource));
consentHistory.add(consentResourceJSON);
Expand Down Expand Up @@ -285,6 +280,14 @@ private void deactivateAccountMappings(DetailedConsentResource detailedConsentRe
}

this.consentCoreService.deactivateAccountMappings(mappingIds);

if (mappingIds.size() == consentMappings.size()) {
// If all the mappings are being deactivated, revoke the consent
this.consentCoreService.revokeConsentWithReason(detailedConsentResource.getConsentID(),
CONSENT_STATUS_REVOKED, null, ConsentCoreServiceConstants.CONSENT_REVOKE_FROM_DASHBOARD_REASON);
log.info(String.format("Consent %s revoked as all the mappings are being deactivated",
detailedConsentResource.getConsentID()));
}
}
//store joint account withdrawal from the consent to consent amendment history
this.storeJointAccountWithdrawalHistory(detailedConsentResource);
Expand All @@ -296,12 +299,15 @@ private void revokeConsentAsPrimaryUser(DetailedConsentResource detailedConsentR
String consentID = detailedConsentResource.getConsentID();
this.consentCoreService.revokeConsentWithReason(consentID, CONSENT_STATUS_REVOKED, null,
ConsentCoreServiceConstants.CONSENT_REVOKE_FROM_DASHBOARD_REASON);
// revoke access tokens
try {
consentCoreService.revokeTokens(detailedConsentResource, userId);
} catch (IdentityOAuth2Exception e) {
log.error(String.format("Error occurred while revoking tokens. Only the consent was revoked " +
"successfully. %s", e.getMessage()));
// revoke access tokens if the user is not null. User can be null if the consent is revoked by a user with
// CustomerCareOfficer role in consent manager.
if (userId != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are we revoking the tokens in CustomerCareOfficer scenario?

try {
consentCoreService.revokeTokens(detailedConsentResource, userId);
} catch (IdentityOAuth2Exception e) {
log.error(String.format("Error occurred while revoking tokens. Only the consent was revoked " +
anjuchamantha marked this conversation as resolved.
Show resolved Hide resolved
"successfully. %s", e.getMessage()));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import { getUserId } from '../services/cdsUtils.js';
*/
export const getConsentHistoryFromAPI = (consentId, user) => {
const userId = getUserId(user);
const consentHistoryUrl = `${CONFIG.BACKEND_URL}/admin/consent-amendment-history?cdrArrangementID=${consentId}&userID=${userId}`;
const consentHistoryAdminUrl = `${CONFIG.BACKEND_URL}/admin/consent-amendment-history?cdrArrangementID=${consentId}`;
const consentHistoryDefaultUrl = `${CONFIG.BACKEND_URL}/admin/consent-amendment-history?cdrArrangementID=${consentId}&userID=${userId}`;
const consentHistoryUrl = (user.role === "customerCareOfficer") ? consentHistoryAdminUrl : consentHistoryDefaultUrl;

const requestConfig = {
headers: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ export const usePermissionData = (permissionData) => {
: permissionDataLanguageIndividual;

const accountList = permissionData.permissionData.previousConsentData.userList;
const matchedUser = accountList.find(u => u.userId === user.email);
let matchedUser;
if (user.role === "customerCareOfficer") {
// If the user is a customer care officer, the primary member's account list is shown
matchedUser = accountList.find(u => u.authType === "primary_member");
} else {
matchedUser = accountList.find(u => u.userId === user.email);
}
const accountArray = matchedUser['accountList'];
const permissionArray = permissionData.permissionData.previousConsentData.permissions;
const sharingDuration = permissionData.permissionData.previousConsentData.sharingDuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const AccountsInfo = ({ consent }) => {
<hr id = "sharingDetailsHr" className = "horizontalLine" />
<h5>{keyDatesConfig.accountsInfoLabel}</h5>
{uniqueActiveAccountIds.map((accountId, index) => (
<li key={index}>{accountId}</li>
<li className="permittedAccount" key={index}>{accountId}</li>
))}
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ export const Accreditation = ({ infoLabel, dataRecipientName, applicationName })
<>
<h6>{infoLabel.accreditation.accreditationLabel}</h6>
<p>
{dataRecipientName} {infoLabel.accreditation.accreditWebsite} [
{dataRecipientName} {infoLabel.accreditation.accreditWebsite}
<a href={infoLabel.accreditation.accreditWebsiteLink} target="_blank" rel="noreferrer">
{/* add website link */}
{infoLabel.accreditation.accreditWebsiteLinkText}
</a>
]
.
</p>
<div className="accredBox">
<img id="logo" src={CDRLogo} alt="CDR" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ export const DetailedAgreement = ({ match }) => {
return getInfoLabel(labels[0], consent);
});

useEffect(() => {
const matchedConsentId = match.params.id;
let matchedConsent = consents.data.filter(
(consent) => consent.consentId === matchedConsentId
);
setConsent(matchedConsent[0]);
}, [consents]);

useEffect(() => {
const labels = lang[consentTypeKey].filter((lbl) =>
lbl.id.split(',').some((x) => x.toLowerCase() === consent.currentStatus.toLowerCase())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const PermissionItem = ({ permissionScope, permissionDataLanguage }) => {
<Card className="clusterContainer">
<Accordion.Toggle className="clusterRow" onClick={toggle} as={Card.Header} eventKey="0">
<Col className="clusterLabel">
<h6>{filteredDataLang.dataCluster}</h6>
<h6 className="clusterLabelText">{filteredDataLang.dataCluster}</h6>
</Col>
<Col className="arrow">
<FontAwesomeIcon
Expand All @@ -68,11 +68,11 @@ export const PermissionItem = ({ permissionScope, permissionDataLanguage }) => {
<Accordion.Collapse eventKey="0">
<Card.Body>
<Container className = "cluster-card-container">
<Row>
<Row className="permissionsUL">
{filteredDataLang.permissions.map((index, idx) => (
<Col xs={12} sm={6} md={6} lg={4} key={idx}>
<ul>
<li>{index}</li>
<li className="permissionText">{index}</li>
</ul>
</Col>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you 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 React, {useState} from "react";
import {Container} from "react-bootstrap";
import {Link} from "react-router-dom";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faDownload } from '@fortawesome/free-solid-svg-icons';
import {withdrawLang, lang} from "../specConfigs";
import ADRLogo from "../images/ADRLogo.png";
import moment from "moment";
import {specConfigurations} from "../specConfigs/specConfigurations";
import { getExpireTimeFromConsent } from "../services/utils";
import { generatePDF } from "../../../toolkit/src/services/cdsUtils";


export const ProfileMain = ({consent, infoLabel, appicationName, logoURL}) => {

const [isImageError, setIsImageError] = useState(false);
const consentConsentId = consent.consentId;
const currentDate = moment().format("YYYY-MM-DDTHH:mm:ss[Z]");

const handleImageError = () => {
setIsImageError(true);
};

if (logoURL === undefined || logoURL === '') {
logoURL = ADRLogo
}

function isNotExpired() {
try {
let expireTimeFromConsent = getExpireTimeFromConsent(consent, "YYYY-MM-DDTHH:mm:ss[Z]");
if (!expireTimeFromConsent) {
return true;
}
return moment(currentDate)
.isBefore(expireTimeFromConsent);
} catch (e) {
return true;
}
}

const consentStatusLabel = (consent.currentStatus.toLowerCase() ===
specConfigurations.status.authorised.toLowerCase() && !isNotExpired())
? specConfigurations.status.expired : infoLabel.label;
return (
<Container className="profileMain">
<img id="profileLogo" onError={handleImageError} src={isImageError ? ADRLogo : logoURL} width="50" height="50"/>
<h4 className="mt-3">{appicationName}</h4>
<>
<div className="confirmLink">
<a id="confirmationReportLink" href="javascript:void(0);"
onClick={() => generatePDF(consent, appicationName, consentStatusLabel)}>
{`${infoLabel.profile.confirmation} `}
<FontAwesomeIcon icon={faDownload} size="2xs" id= "downloadIcon"/>
</a>
</div>
{consent.currentStatus.toLowerCase() ===
specConfigurations.status.authorised.toLowerCase() && isNotExpired() ? (
<div className="actionButtons">
<div className="actionBtnDiv">
<Link
to={`/consentmgr/${consentConsentId}/withdrawal-step-1`}
className="withdrawBtn"
>
{withdrawLang.detailedConsentPageStopSharingBtn}
</Link>
</div>
</div>
) : (
<div className="actionButtons">
</div>
)
}
</>
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
* specific language governing permissions and limitations
* under the License.
*/

import moment from 'moment'
import jsPDF from "jspdf";
import { specConfigurations } from '../specConfigs/specConfigurations.js';
import { dataTypes } from '../specConfigs/common.js';
import { dataTypes, consentPdfProperties } from '../specConfigs/common.js';

export const getAmendmendedReason = (amendedReason) => {
const reason = Object.entries(
Expand All @@ -40,9 +42,95 @@ export const convertSecondsToDaysHoursMinutes = (seconds) => {
};

export const getUserId = (user) => {
return user.email.endsWith('@carbon.super') ? user.email : user.email + '@carbon.super';
};
return user.email.endsWith('@carbon.super') ? user.email : user.email + '@carbon.super';
};

export const getTimeStamp = (timestamp) => {
return moment(timestamp * 1000).format(dataTypes.daysHours);
};

export function generatePDF(consent, applicationName, consentStatus) {

const pdf = new jsPDF(consentPdfProperties.orientation, consentPdfProperties.measurement, consentPdfProperties.size);
pdf.setFontSize(consentPdfProperties.fontSize);
pdf.rect(10, 10, 190, 275);

const keyDateTitles = document.getElementsByClassName('keyDateTitle');
const keyDateValues = document.getElementsByClassName('keyDateValue');
const permissionCategories = document.getElementsByClassName('clusterLabelText');
const permissions = document.getElementsByClassName('permissionsUL');
const accountIDs = document.getElementsByClassName('permittedAccount');

let contents = [];
let accounts = [];

try {

for (let i = 0; i < permissions.length; i++) {
let permissionTexts = permissions[i].getElementsByClassName('permissionText');
let permissionTextsJoined = "";
for (let j = 0; j < permissionTexts.length; j++) {
permissionTextsJoined += permissionTexts[j].innerHTML;
if (j < permissionTexts.length - 1) {
permissionTextsJoined += ", ";
}
}
contents.push(permissionTextsJoined);
}

for (let i = 0; i < accountIDs.length; i++) {
accounts.push(accountIDs[i].innerHTML);
}

} catch (e) {
}

let x = 20;
let y = 20;

pdf.text(x, y, 'Consent ID : ' + consent.consentId);
y += 10;
pdf.text(x, y, 'Status : ' + consentStatus);
y += 10;
pdf.text(x, y, 'API Consumer Application : ' + applicationName);
y += 10;
for (let i = 0; i < keyDateTitles.length; i++) {
pdf.text(x, y, keyDateTitles[i].innerHTML + ' ' + keyDateValues[i].innerHTML);
y += 10;
}
if (accounts.length > 0) {
pdf.text(x, y, 'Accounts : ' + accounts.join(', '));
y += 10;
}
pdf.text(x, y, 'Data we are sharing on : ');
y += 10;

const maxWidth = 140; // Maximum width of the text in the PDF
const lineHeight = 5; // Height between lines

for (let i = 0; i < contents.length; i++) {
const categoryText = permissionCategories[i].innerHTML + ' :';
const contentText = contents[i];

// Split the category text and content text to fit within the maxWidth
const categoryLines = pdf.splitTextToSize(categoryText, maxWidth - 10);
const contentLines = pdf.splitTextToSize(contentText, maxWidth);

// Add each line of the category text
categoryLines.forEach((line, index) => {
pdf.text(30, y + (index * lineHeight), line);
});

// Adjust yPosition for the content text
y += categoryLines.length * lineHeight;

// Add each line of the content text
contentLines.forEach((line, index) => {
pdf.text(40, y + (index * lineHeight), line);
});

// Adjust yPosition for the next category
y += contentLines.length * lineHeight + lineHeight;
}
pdf.save("consent_" + consent.consentId + ".pdf");
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
*/

export const common = {
footerContent: 'WSO2 Open Banking | ' + new Date().getFullYear(),
complaintHandleLinkText: 'Complaint handling and resolution',
footerContent: 'WSO2 Open Banking Solution | ' + new Date().getFullYear()
};

export const keyDateTypes = {
Expand Down Expand Up @@ -54,7 +53,7 @@ export const dataTypes = {
// To indicate the dataType is a ISO 8601 date
timestamp: 'DATE_TIMESTAMP',
// To Display date in 'YYYY-MM-DD' format and time in 'hh:mm A' format
daysHours: 'YYYY-MM-DD hh:mm A',
daysHours: 'YYYY-MM-DD hh:mm:ss A',
};

export const keyValues = {
Expand Down Expand Up @@ -92,3 +91,10 @@ export const consentTypes = [
image: require('../../../accelerator/src/images/accounts.png'),
},
];

export const consentPdfProperties = {
orientation: "p",
measurement: "mm",
pageSize: "a4",
fontSize: "11"
};
Loading
Loading