diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/config/ActivityLogConfig.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/config/ActivityLogConfig.java index fa515ad30..4c1775960 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/config/ActivityLogConfig.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/config/ActivityLogConfig.java @@ -17,16 +17,17 @@ */ package org.hyperledger.bpa.config; -import lombok.NoArgsConstructor; +import lombok.Getter; import org.hyperledger.aries.api.connection.ConnectionState; import org.hyperledger.aries.api.present_proof.PresentationExchangeState; import javax.inject.Inject; import javax.inject.Singleton; +import java.util.ArrayList; import java.util.List; @Singleton -@NoArgsConstructor +@Getter public class ActivityLogConfig { /* * For now, we are not sure what to do with this configuration. Will each @@ -35,58 +36,64 @@ public class ActivityLogConfig { * AcaPyConfig, which flags are set to auto respond... */ - @Inject - AcaPyConfig acaPyConfig; + private static List CONNECTION_STATES_TASKS = List.of(ConnectionState.REQUEST); - public List getConnectionStatesForActivities() { - return connectionStates(ConnectionState.REQUEST, ConnectionState.INVITATION, ConnectionState.ACTIVE, - ConnectionState.RESPONSE); - } + private static List CONNECTION_STATES_COMPLETED = List.of(ConnectionState.ACTIVE, + ConnectionState.RESPONSE, + ConnectionState.COMPLETED, + ConnectionState.PING_RESPONSE, + ConnectionState.PING_NO_RESPONSE); - public List getConnectionStatesForTasks() { - if (this.isConnectionRequestTask()) { - return connectionStates(ConnectionState.REQUEST); - } - return List.of(); - } + private static List PRESENTATION_EXCHANGE_STATES_TASKS = List.of(PresentationExchangeState.REQUEST_RECEIVED); - public List getConnectionStatesCompleted() { - return connectionStates(ConnectionState.ACTIVE, ConnectionState.RESPONSE); - } + private static List PRESENTATION_EXCHANGE_STATES_COMPLETED = List.of(PresentationExchangeState.VERIFIED, + PresentationExchangeState.PRESENTATION_ACKED); - public boolean isConnectionRequestTask() { - return !acaPyConfig.getAutoAcceptRequests(); - } + private List connectionStatesForActivities; + private List connectionStatesForCompleted; + private List connectionStatesForTasks; + private List presentationExchangeStatesForActivities; + private List presentationExchangeStatesForCompleted; + private List presentationExchangeStatesForTasks; - public List getPresentationExchangeStatesForActivities() { - return presentationExchangeStates(PresentationExchangeState.REQUEST_RECEIVED, - PresentationExchangeState.REQUEST_SENT, - PresentationExchangeState.VERIFIED, - PresentationExchangeState.PRESENTATION_ACKED); - } + private AcaPyConfig acaPyConfig; + + @Inject + ActivityLogConfig(AcaPyConfig acaPyConfig) { + this.acaPyConfig = acaPyConfig; + // 1. set the tasks lists first as they depend on aca py configuration + connectionStatesForTasks = this.isConnectionRequestTask() ? CONNECTION_STATES_TASKS : List.of(); + presentationExchangeStatesForTasks = this.isPresentationExchangeTask() ? PRESENTATION_EXCHANGE_STATES_TASKS : List.of(); + + // 2. set the completed state lists + connectionStatesForCompleted = CONNECTION_STATES_COMPLETED; + presentationExchangeStatesForCompleted = PRESENTATION_EXCHANGE_STATES_COMPLETED; - public List getPresentationExchangeStatesForTasks() { - if (this.isPresentationExchangeTask()) { - return presentationExchangeStates(PresentationExchangeState.REQUEST_RECEIVED); - } - return List.of(); + // 3. build the activity lists based on task and completed lists + connectionStatesForActivities = this.buildConnectionStatesForActivities(); + presentationExchangeStatesForActivities = this.buildPresentationExchangeStatesForActivities(); } - public List getPresentationExchangeStatesCompleted() { - return presentationExchangeStates(PresentationExchangeState.VERIFIED, - PresentationExchangeState.PRESENTATION_ACKED); + private List buildConnectionStatesForActivities() { + List results = new ArrayList<>(this.getConnectionStatesForCompleted()); + results.addAll(this.getConnectionStatesForTasks()); + results.add(ConnectionState.INVITATION); + return List.copyOf(results); } - public boolean isPresentationExchangeTask() { - return !acaPyConfig.getAutoRespondPresentationRequest(); + private boolean isConnectionRequestTask() { + return !this.acaPyConfig.getAutoAcceptRequests(); } - private List connectionStates(ConnectionState... states) { - return List.of(states); + public List buildPresentationExchangeStatesForActivities() { + List results = new ArrayList<>(this.getPresentationExchangeStatesForCompleted()); + results.addAll(this.getPresentationExchangeStatesForTasks()); + results.add(PresentationExchangeState.REQUEST_SENT); + return List.copyOf(results); } - private List presentationExchangeStates(PresentationExchangeState... states) { - return List.of(states); + private boolean isPresentationExchangeTask() { + return !this.acaPyConfig.getAutoRespondPresentationRequest(); } } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/ActivitiesController.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/ActivitiesController.java index 2c96c7838..d74aa8e14 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/ActivitiesController.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/ActivitiesController.java @@ -28,7 +28,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.hyperledger.bpa.controller.api.activity.ActivityItem; import org.hyperledger.bpa.controller.api.activity.ActivitySearchParameters; -import org.hyperledger.bpa.impl.ActivitiesManager; +import org.hyperledger.bpa.impl.ActivityManager; import javax.inject.Inject; import javax.validation.Valid; @@ -41,7 +41,7 @@ public class ActivitiesController { @Inject - ActivitiesManager activitiesManager; + ActivityManager activityManager; /** * List Items, if no filters return all @@ -51,7 +51,7 @@ public class ActivitiesController { */ @Get public HttpResponse> listActivities(@RequestBean @Valid ActivitySearchParameters parameters) { - return HttpResponse.ok(activitiesManager.getItems(parameters)); + return HttpResponse.ok(activityManager.getItems(parameters)); } } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/WebSocketMessageBody.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/WebSocketMessageBody.java index 2f0a519bf..38ac1a4b5 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/WebSocketMessageBody.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/WebSocketMessageBody.java @@ -17,11 +17,10 @@ */ package org.hyperledger.bpa.controller.api; +import io.micronaut.core.annotation.Nullable; import lombok.*; import org.hyperledger.aries.api.message.BasicMessage; import org.hyperledger.bpa.api.PartnerAPI; -import org.hyperledger.bpa.api.aries.AriesCredential; -import org.hyperledger.bpa.api.aries.AriesProofExchange; /** * Websocket events @@ -44,81 +43,50 @@ public class WebSocketMessageBody { @Builder public static final class WebSocketMessage { private WebSocketMessageType type; - private WebSocketMessageState state; private String linkId; private Object info; + private PartnerAPI partner; } public enum WebSocketMessageType { - CONNECTION_REQUEST, - CREDENTIAL, - PARTNER, - PROOF, - PROOFREQUEST, - NOTIFICATION, - MESSAGE + ON_MESSAGE_RECEIVED, + ON_CREDENTIAL_ADDED, + ON_PARTNER_REQUEST_COMPLETED, + ON_PARTNER_REQUEST_RECEIVED, + ON_PARTNER_ADDED, + ON_PARTNER_ACCEPTED, + ON_PARTNER_REMOVED, + ON_PRESENTATION_VERIFIED, + ON_PRESENTATION_PROVED, + ON_PRESENTATION_REQUEST_DECLINED, + ON_PRESENTATION_REQUEST_DELETED, + ON_PRESENTATION_REQUEST_RECEIVED, + ON_PRESENTATION_REQUEST_SENT, + TASK_ADDED, + TASK_COMPLETED } - public enum WebSocketMessageState { - RECEIVED, - UPDATED, - SENT, - NEW, - COMPLETED - } - - public static WebSocketMessageBody partnerReceived(PartnerAPI partner) { - return WebSocketMessageBody.of(WebSocketMessage - .builder() - .type(WebSocketMessageType.PARTNER) - .state(WebSocketMessageState.RECEIVED) - .linkId(partner.getId()) - .info(partner) - .build()); - } - - public static WebSocketMessageBody credentialReceived(AriesCredential credential) { - return WebSocketMessageBody.of(WebSocketMessage - .builder() - .type(WebSocketMessageType.CREDENTIAL) - .state(WebSocketMessageState.RECEIVED) - .linkId(credential.getId().toString()) - .info(credential) - .build()); + public static WebSocketMessageBody message(PartnerAPI partner, BasicMessage message) { + return notificationEvent(WebSocketMessageType.ON_MESSAGE_RECEIVED, + partner.getId(), + PartnerMessage.builder() + .partnerId(partner.getId()) + .messageId(message.getMessageId()) + .content(message.getContent()) + .build(), + partner); } - public static WebSocketMessageBody proof( - @NonNull WebSocketMessageState state, - @NonNull WebSocketMessageType type, - @NonNull AriesProofExchange proof) { + public static WebSocketMessageBody notificationEvent(@NonNull WebSocketMessageType type, + @Nullable String linkId, + @Nullable Object info, + @Nullable PartnerAPI partner) { return WebSocketMessageBody.of(WebSocketMessage .builder() .type(type) - .state(state) - .linkId(proof.getId().toString()) - .info(proof) - .build()); - } - - public static WebSocketMessageBody notification(Object info, Boolean completed) { - return WebSocketMessageBody.of(WebSocketMessage - .builder() - .type(WebSocketMessageType.NOTIFICATION) - .state(completed ? WebSocketMessageState.COMPLETED : WebSocketMessageState.NEW) .info(info) - .build()); - } - - public static WebSocketMessageBody message(PartnerAPI partner, BasicMessage message) { - return WebSocketMessageBody.of(WebSocketMessage - .builder() - .type(WebSocketMessageType.MESSAGE) - .state(WebSocketMessageState.RECEIVED) - .info(PartnerMessage.builder() - .partnerId(partner.getId()) - .messageId(message.getMessageId()) - .content(message.getContent()) - .build()) + .partner(partner) + .linkId(linkId) .build()); } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityItem.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityItem.java index d66cb0556..a5a609242 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityItem.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityItem.java @@ -29,11 +29,12 @@ @Builder public class ActivityItem { + private String id; private ActivityRole role; private ActivityState state; private ActivityType type; private Long updatedAt; private String linkId; private PartnerAPI partner; - private Boolean task; + private Boolean completed; } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityRole.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityRole.java index 8c65ea4cb..c0b80df4c 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityRole.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityRole.java @@ -29,5 +29,5 @@ public enum ActivityRole { @JsonProperty("presentation_exchange_prover") PRESENTATION_EXCHANGE_PROVER, @JsonProperty("presentation_exchange_verifier") - PRESENTATION_EXCHANGE_VERIFIER + PRESENTATION_EXCHANGE_VERIFIER, } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityState.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityState.java index 74f4d8ad9..77d8e1701 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityState.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/controller/api/activity/ActivityState.java @@ -33,5 +33,8 @@ public enum ActivityState { @JsonProperty("presentation_exchange_received") PRESENTATION_EXCHANGE_RECEIVED, @JsonProperty("presentation_exchange_accepted") - PRESENTATION_EXCHANGE_ACCEPTED + PRESENTATION_EXCHANGE_ACCEPTED, + @JsonProperty("presentation_exchange_declined") + PRESENTATION_EXCHANGE_DECLINED, + } diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesEventHandler.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesEventHandler.java deleted file mode 100644 index 68d556352..000000000 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesEventHandler.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020-2021 - for information on the respective copyright owner - * see the NOTICE file and/or the repository at - * https://github.com/hyperledger-labs/business-partner-agent - * - * 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. - */ -package org.hyperledger.bpa.impl; - -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.hyperledger.aries.api.connection.ConnectionRecord; -import org.hyperledger.aries.api.message.BasicMessage; -import org.hyperledger.aries.api.present_proof.PresentationExchangeRecord; -import org.hyperledger.aries.webhook.EventHandler; -import org.hyperledger.bpa.api.PartnerAPI; -import org.hyperledger.bpa.config.ActivityLogConfig; -import org.hyperledger.bpa.controller.api.WebSocketMessageBody; -import org.hyperledger.bpa.controller.api.activity.ActivityType; - -import javax.inject.Inject; -import javax.inject.Singleton; - -@Slf4j -@Singleton -@NoArgsConstructor -public class ActivitiesEventHandler extends EventHandler { - @Inject - MessageService messageService; - - @Inject - ActivityLogConfig activityLogConfig; - - @Inject - PartnerManager partnerManager; - - @Override - public void handleConnection(ConnectionRecord connection) { - Boolean completed = null; - boolean notify = true; - if (activityLogConfig.getConnectionStatesForTasks().contains(connection.getState())) { - completed = false; - // we do not always want to notify... it is only a task on incoming request - notify = connection.isIncomingConnection(); - } else if (activityLogConfig.getConnectionStatesCompleted().contains(connection.getState())) { - completed = true; - } - if (completed != null && notify) { - messageService - .sendMessage(WebSocketMessageBody.notification(ActivityType.CONNECTION_REQUEST, completed)); - } - } - - @Override - public void handleProof(PresentationExchangeRecord proof) { - Boolean completed = null; - if (activityLogConfig.getPresentationExchangeStatesForTasks().contains(proof.getState())) { - completed = false; - } else if (activityLogConfig.getPresentationExchangeStatesCompleted().contains(proof.getState())) { - completed = true; - } - if (completed != null) { - messageService - .sendMessage(WebSocketMessageBody.notification(ActivityType.PRESENTATION_EXCHANGE, completed)); - } - } - - @Override - public void handleBasicMessage(BasicMessage message) { - PartnerAPI partner = partnerManager.getPartnerByConnectionId(message.getConnectionId()); - if (partner != null) { - messageService.sendMessage(WebSocketMessageBody.message(partner, message)); - } - } - -} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesManager.java deleted file mode 100644 index 7cbdaaf9d..000000000 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivitiesManager.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2020-2021 - for information on the respective copyright owner - * see the NOTICE file and/or the repository at - * https://github.com/hyperledger-labs/business-partner-agent - * - * 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. - */ -package org.hyperledger.bpa.impl; - -import io.micronaut.core.annotation.Nullable; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.hyperledger.aries.api.connection.ConnectionState; -import org.hyperledger.aries.api.present_proof.PresentationExchangeRole; -import org.hyperledger.aries.api.present_proof.PresentationExchangeState; -import org.hyperledger.bpa.api.PartnerAPI; -import org.hyperledger.bpa.config.ActivityLogConfig; -import org.hyperledger.bpa.controller.api.activity.*; -import org.hyperledger.bpa.model.Partner; -import org.hyperledger.bpa.model.PartnerProof; -import org.hyperledger.bpa.repository.PartnerProofRepository; -import org.hyperledger.bpa.repository.PartnerRepository; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.UUID; - -@Slf4j -@NoArgsConstructor -public class ActivitiesManager { - - @Inject - PartnerRepository partnerRepo; - - @Inject - PartnerProofRepository proofRepository; - - @Inject - ActivityLogConfig activityLogConfig; - - @Inject - PartnerManager partnerManager; - - private List getActivityListItems(@NonNull ActivitySearchParameters parameters) { - List results = new ArrayList<>(); - if (parameters.getActivity() == null || parameters.getActivity()) { - // connection invitations... outgoing. - results.addAll(getConnectionRequests(parameters.getType(), - activityLogConfig.getConnectionStatesForActivities(), false)); - results.addAll( - getPresentationExchanges(parameters.getType(), - activityLogConfig.getPresentationExchangeStatesForActivities(), false)); - } - return results; - } - - private List getTaskListItems(@NonNull ActivitySearchParameters parameters) { - List results = new ArrayList<>(); - if (parameters.getTask() == null || parameters.getTask()) { - results.addAll(getConnectionRequests(parameters.getType(), - activityLogConfig.getConnectionStatesForTasks(), true)); - results.addAll(getPresentationExchanges(parameters.getType(), - activityLogConfig.getPresentationExchangeStatesForTasks(), true)); - } - return results; - } - - public List getItems(ActivitySearchParameters parameters) { - List results = new ArrayList<>(); - results.addAll(getActivityListItems(parameters)); - results.addAll(getTaskListItems(parameters)); - results.sort(Comparator.comparingLong(ActivityItem::getUpdatedAt).reversed()); - return results; - } - - private List getConnectionRequests(@Nullable ActivityType type, List states, - Boolean incoming) { - List results = new ArrayList<>(); - if (type == null || type == ActivityType.CONNECTION_REQUEST) { - Iterable partners = partnerRepo.findByStateIn(states); - for (Partner p : partners) { - if (incoming) { - // then we are looking for tasks... - if (p.getIncoming() != null) { - results.add(getConnectionRequestItem(p, true)); - } - } else { - results.add(getConnectionRequestItem(p, false)); - } - } - } - return results; - } - - private List getPresentationExchanges(@Nullable ActivityType type, - List states, Boolean task) { - List results = new ArrayList<>(); - if (type == null || type == ActivityType.PRESENTATION_EXCHANGE) { - Iterable proofs = proofRepository.findByStateIn(states); - for (PartnerProof p : proofs) { - results.add(getPresentationExchangeItem(p, task)); - } - } - return results; - } - - private ActivityItem getConnectionRequestItem(@NonNull Partner p, Boolean task) { - ActivityRole role = (p.getIncoming() == null) ? ActivityRole.CONNECTION_REQUEST_SENDER - : ActivityRole.CONNECTION_REQUEST_RECIPIENT; - ActivityType type = ActivityType.CONNECTION_REQUEST; - - ActivityState state; - switch (p.getState()) { - case ACTIVE: - case RESPONSE: - state = ActivityState.CONNECTION_REQUEST_ACCEPTED; - break; - default: - if (role == ActivityRole.CONNECTION_REQUEST_SENDER) { - state = ActivityState.CONNECTION_REQUEST_SENT; - } else { - state = ActivityState.CONNECTION_REQUEST_RECEIVED; - } - } - - Long updatedAt = p.getUpdatedAt().toEpochMilli(); - UUID linkId = p.getId(); - PartnerAPI apiPartner = partnerManager.getPartner(linkId); - return ActivityItem.builder() - .role(role) - .state(state) - .type(type) - .partner(apiPartner) - .linkId(linkId.toString()) - .task(task) - .updatedAt(updatedAt) - .build(); - } - - private ActivityItem getPresentationExchangeItem(@NonNull PartnerProof p, Boolean task) { - ActivityRole role = p.getRole() == PresentationExchangeRole.PROVER ? ActivityRole.PRESENTATION_EXCHANGE_PROVER - : ActivityRole.PRESENTATION_EXCHANGE_VERIFIER; - ActivityType type = ActivityType.PRESENTATION_EXCHANGE; - - ActivityState state; - switch (p.getState()) { - case VERIFIED: - case PRESENTATION_ACKED: - state = ActivityState.PRESENTATION_EXCHANGE_ACCEPTED; - break; - case REQUEST_SENT: - case PRESENTATIONS_SENT: - state = ActivityState.PRESENTATION_EXCHANGE_SENT; - break; - case REQUEST_RECEIVED: - case PRESENTATION_RECEIVED: - state = ActivityState.PRESENTATION_EXCHANGE_RECEIVED; - break; - default: - if (role == ActivityRole.PRESENTATION_EXCHANGE_PROVER) { - state = ActivityState.PRESENTATION_EXCHANGE_SENT; - } else { - state = ActivityState.PRESENTATION_EXCHANGE_RECEIVED; - } - } - - UUID linkId = p.getPartnerId(); - PartnerAPI apiPartner = partnerManager.getPartner(linkId); - Long updatedAt = (p.getIssuedAt() != null) ? p.getIssuedAt().toEpochMilli() : p.getCreatedAt().toEpochMilli(); - - return ActivityItem.builder() - .role(role) - .state(state) - .type(type) - .partner(apiPartner) - .linkId(linkId.toString()) - .task(task) - .updatedAt(updatedAt) - .build(); - } - -} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivityManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivityManager.java new file mode 100644 index 000000000..b1f887810 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/ActivityManager.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl; + +import io.micronaut.context.event.ApplicationEventPublisher; +import io.micronaut.core.annotation.NonNull; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.hyperledger.aries.api.present_proof.PresentationExchangeRole; +import org.hyperledger.bpa.config.ActivityLogConfig; +import org.hyperledger.bpa.controller.api.activity.*; +import org.hyperledger.bpa.impl.notification.TaskAddedEvent; +import org.hyperledger.bpa.impl.notification.TaskCompletedEvent; +import org.hyperledger.bpa.impl.util.Converter; +import org.hyperledger.bpa.model.Activity; +import org.hyperledger.bpa.model.Partner; +import org.hyperledger.bpa.model.PartnerProof; +import org.hyperledger.bpa.repository.ActivityRepository; +import org.hyperledger.bpa.repository.PartnerProofRepository; +import org.hyperledger.bpa.repository.PartnerRepository; +import org.jetbrains.annotations.NotNull; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@NoArgsConstructor +public class ActivityManager { + + @Inject + PartnerRepository partnerRepo; + + @Inject + PartnerProofRepository proofRepository; + + @Inject + ActivityLogConfig activityLogConfig; + + @Inject + ActivityRepository activityRepository; + + @Inject + Converter converter; + + @Inject + ApplicationEventPublisher eventPublisher; + + public List getItems(ActivitySearchParameters parameters) { + List activities = new ArrayList<>(); + + if (parameters.getActivity() && parameters.getTask()) { + if (parameters.getType() != null) { + activities = activityRepository.findByTypeOrderByUpdatedAt(parameters.getType()); + } else { + activities = activityRepository.listOrderByUpdatedAtDesc(); + } + } else if (parameters.getTask()) { + if (parameters.getType() != null) { + activities = activityRepository + .findByTypeAndCompletedFalseOrderByUpdatedAtDesc(parameters.getType()); + } else { + activities = activityRepository.findByCompletedFalseOrderByUpdatedAtDesc(); + } + } else { + if (parameters.getType() != null) { + activities = activityRepository + .findByTypeAndCompletedTrueOrderByUpdatedAtDesc(parameters.getType()); + } else { + activities = activityRepository.findByCompletedTrueOrderByUpdatedAtDesc(); + } + } + + return activities.stream().map(this::convert).collect(Collectors.toList()); + } + + public void addPartnerRequestReceivedTask(@NonNull Partner partner) { + // in case event is fired multiple times + Optional existing = activityRepository.findByLinkIdAndTypeAndRole(partner.getId(), + ActivityType.CONNECTION_REQUEST, + ActivityRole.CONNECTION_REQUEST_RECIPIENT); + if (existing.isEmpty()) { + Activity a = Activity.builder() + .linkId(partner.getId()) + .partner(partner) + .type(ActivityType.CONNECTION_REQUEST) + .role(ActivityRole.CONNECTION_REQUEST_RECIPIENT) + .state(ActivityState.CONNECTION_REQUEST_RECEIVED) + .completed(false) + .build(); + activityRepository.save(a); + eventPublisher.publishEventAsync(TaskAddedEvent.builder().activity(a).build()); + } + } + + public void completePartnerRequestTask(@NonNull Partner partner) { + activityRepository.findByLinkIdAndTypeAndRole(partner.getId(), + ActivityType.CONNECTION_REQUEST, + ActivityRole.CONNECTION_REQUEST_RECIPIENT).ifPresentOrElse(activity -> { + // set to completed and mark accepted + activity.setState(ActivityState.CONNECTION_REQUEST_ACCEPTED); + activity.setCompleted(true); + activityRepository.update(activity); + eventPublisher.publishEventAsync(TaskCompletedEvent.builder().activity(activity).build()); + }, () -> { + // add in a completed activity + Activity a = Activity.builder() + .linkId(partner.getId()) + .partner(partner) + .type(ActivityType.CONNECTION_REQUEST) + .role(ActivityRole.CONNECTION_REQUEST_RECIPIENT) + .state(ActivityState.CONNECTION_REQUEST_ACCEPTED) + .completed(true) + .build(); + activityRepository.save(a); + }); + } + + public void deletePartnerActivities(@NonNull Partner partner) { + activityRepository.deleteByPartnerId(partner.getId()); + } + + public void addPartnerAddedActivity(@NonNull Partner partner) { + Optional existing = activityRepository.findByLinkIdAndTypeAndRole(partner.getId(), + ActivityType.CONNECTION_REQUEST, + ActivityRole.CONNECTION_REQUEST_SENDER); + if (existing.isEmpty()) { + Activity a = Activity.builder() + .linkId(partner.getId()) + .partner(partner) + .type(ActivityType.CONNECTION_REQUEST) + .role(ActivityRole.CONNECTION_REQUEST_SENDER) + .state(ActivityState.CONNECTION_REQUEST_SENT) + .completed(true) + .build(); + activityRepository.save(a); + } + } + + public void addPartnerAcceptedActivity(@NonNull Partner partner) { + activityRepository.findByLinkIdAndTypeAndRole(partner.getId(), + ActivityType.CONNECTION_REQUEST, + ActivityRole.CONNECTION_REQUEST_SENDER).ifPresentOrElse(activity -> { + activity.setState(ActivityState.CONNECTION_REQUEST_ACCEPTED); + activity.setCompleted(true); + activityRepository.update(activity); + }, () -> { + // add in a completed activity + Activity a = Activity.builder() + .linkId(partner.getId()) + .partner(partner) + .type(ActivityType.CONNECTION_REQUEST) + .role(ActivityRole.CONNECTION_REQUEST_SENDER) + .state(ActivityState.CONNECTION_REQUEST_ACCEPTED) + .completed(true) + .build(); + activityRepository.save(a); + }); + } + + public void addPresentationExchangeTask(@NonNull PartnerProof partnerProof) { + partnerRepo.findById(partnerProof.getPartnerId()).ifPresent(partner -> { + // in case event is fired multiple times, see if already exists. + ActivityRole role = getPresentationExchangeRole(partnerProof); + ActivityState state = getPresentationExchangeState(partnerProof); + + Optional existing = activityRepository.findByLinkIdAndTypeAndRole(partnerProof.getId(), + ActivityType.PRESENTATION_EXCHANGE, + role); + + if (existing.isEmpty()) { + Activity a = Activity.builder() + .linkId(partnerProof.getId()) + .partner(partner) + .type(ActivityType.PRESENTATION_EXCHANGE) + .role(role) + .state(state) + .completed(ActivityState.PRESENTATION_EXCHANGE_SENT.equals(state)) + .build(); + activityRepository.save(a); + + if (!a.isCompleted()) { + // this looks like we created a task! + eventPublisher.publishEventAsync(TaskAddedEvent.builder().activity(a).build()); + } + } + }); + } + + public void completePresentationExchangeTask(@NonNull PartnerProof partnerProof) { + partnerRepo.findById(partnerProof.getPartnerId()).ifPresent(partner -> { + // in case event is fired multiple times, see if already exists. + ActivityRole role = getPresentationExchangeRole(partnerProof); + ActivityState state = ActivityState.PRESENTATION_EXCHANGE_ACCEPTED; + + activityRepository.findByLinkIdAndTypeAndRole(partnerProof.getId(), + ActivityType.PRESENTATION_EXCHANGE, + role).ifPresentOrElse(activity -> { + // set to completed and mark accepted + activity.setState(state); + activity.setCompleted(true); + activityRepository.update(activity); + + eventPublisher.publishEventAsync(TaskCompletedEvent.builder().activity(activity).build()); + }, () -> { + // add in a completed activity + Activity a = Activity.builder() + .linkId(partnerProof.getId()) + .partner(partner) + .type(ActivityType.PRESENTATION_EXCHANGE) + .role(role) + .state(state) + .completed(true) + .build(); + activityRepository.save(a); + }); + }); + } + + public void declinePresentationExchangeTask(@NonNull PartnerProof partnerProof) { + partnerRepo.findById(partnerProof.getPartnerId()).ifPresent(partner -> { + // in case event is fired multiple times, see if already exists. + ActivityRole role = getPresentationExchangeRole(partnerProof); + + activityRepository.findByLinkIdAndTypeAndRole(partnerProof.getId(), + ActivityType.PRESENTATION_EXCHANGE, + role).ifPresent(activity -> { + activity.setState(ActivityState.PRESENTATION_EXCHANGE_DECLINED); + activity.setCompleted(true); + activityRepository.update(activity); + eventPublisher.publishEventAsync(TaskCompletedEvent.builder().activity(activity).build()); + }); + }); + } + + public void deletePresentationExchangeTask(@NonNull PartnerProof partnerProof) { + ActivityRole role = getPresentationExchangeRole(partnerProof); + activityRepository.findByLinkIdAndTypeAndRole(partnerProof.getId(), + ActivityType.PRESENTATION_EXCHANGE, + role).ifPresent(activity -> { + activityRepository.delete(activity); + eventPublisher.publishEventAsync(TaskCompletedEvent.builder().activity(activity).build()); + }); + } + + private ActivityItem convert(Activity activity) { + return ActivityItem.builder() + .id(activity.getId().toString()) + .linkId(activity.getLinkId().toString()) + .partner(converter.toAPIObject(activity.getPartner())) + .role(activity.getRole()) + .state(activity.getState()) + .type(activity.getType()) + .updatedAt(activity.getUpdatedAt().toEpochMilli()) + .completed(activity.isCompleted()) + .build(); + } + + private ActivityState getPresentationExchangeState(PartnerProof partnerProof) { + switch (partnerProof.getState()) { + case VERIFIED: + case PRESENTATION_ACKED: + return ActivityState.PRESENTATION_EXCHANGE_ACCEPTED; + case REQUEST_SENT: + case PRESENTATIONS_SENT: + return ActivityState.PRESENTATION_EXCHANGE_SENT; + case REQUEST_RECEIVED: + case PRESENTATION_RECEIVED: + return ActivityState.PRESENTATION_EXCHANGE_RECEIVED; + default: + switch (partnerProof.getRole()) { + case VERIFIER: + return ActivityState.PRESENTATION_EXCHANGE_RECEIVED; + case PROVER: + default: + return ActivityState.PRESENTATION_EXCHANGE_SENT; + } + } + } + + @NotNull + private ActivityRole getPresentationExchangeRole(@NonNull PartnerProof partnerProof) { + return PresentationExchangeRole.PROVER.equals(partnerProof.getRole()) + ? ActivityRole.PRESENTATION_EXCHANGE_PROVER + : ActivityRole.PRESENTATION_EXCHANGE_VERIFIER; + } + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/NotificationEventListener.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/NotificationEventListener.java new file mode 100644 index 000000000..4cd4d3457 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/NotificationEventListener.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl; + +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.annotation.Async; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.hyperledger.aries.api.present_proof.PresentationExchangeRole; +import org.hyperledger.bpa.api.PartnerAPI; +import org.hyperledger.bpa.config.ActivityLogConfig; +import org.hyperledger.bpa.controller.api.WebSocketMessageBody; +import org.hyperledger.bpa.impl.notification.*; +import org.hyperledger.bpa.impl.util.Converter; +import org.hyperledger.bpa.model.PartnerProof; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Optional; + +@Singleton +@Slf4j +public class NotificationEventListener { + + @Inject + PartnerManager partnerManager; + + @Inject + MessageService messageService; + + @Inject + ActivityLogConfig activityLogConfig; + + @Inject + Converter conv; + + @Inject + ActivityManager activityManager; + + @EventListener + @Async + public void onCredentialAddedEvent(CredentialAddedEvent event) { + log.debug("onCredentialAddedEvent"); + // we have the connection id, but not the partner, will need to look up + // partner... + PartnerAPI partnerAPI = partnerManager.getPartnerByConnectionId(event.getCredential().getConnectionId()); + if (partnerAPI != null) { + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_CREDENTIAL_ADDED, + event.getCredential().getId().toString(), + event.getCredential(), + partnerAPI); + messageService.sendMessage(message); + } + } + + @EventListener + @Async + public void onPartnerRequestCompletedEvent(PartnerRequestCompletedEvent event) { + log.debug("onPartnerRequestCompletedEvent"); + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PARTNER_REQUEST_COMPLETED, + event.getPartner().getId().toString(), + null, + conv.toAPIObject(event.getPartner())); + messageService.sendMessage(message); + + activityManager.completePartnerRequestTask(event.getPartner()); + } + + @EventListener + @Async + public void onPartnerRequestReceivedEvent(PartnerRequestReceivedEvent event) { + log.debug("onPartnerRequestReceivedEvent"); + // only notify if this is a task (requires manual intervention) + if (activityLogConfig.getConnectionStatesForTasks().contains(event.getPartner().getState())) { + + activityManager.addPartnerRequestReceivedTask(event.getPartner()); + + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PARTNER_REQUEST_RECEIVED, + event.getPartner().getId().toString(), + null, + conv.toAPIObject(event.getPartner())); + messageService.sendMessage(message); + } + } + + @EventListener + @Async + public void onPartnerAddedEvent(PartnerAddedEvent event) { + log.debug("onPartnerAddedEvent"); + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PARTNER_ADDED, + event.getPartner().getId().toString(), + null, + conv.toAPIObject(event.getPartner())); + messageService.sendMessage(message); + + activityManager.addPartnerAddedActivity(event.getPartner()); + } + + @EventListener + @Async + public void onPartnerAcceptedEvent(PartnerAcceptedEvent event) { + log.debug("onPartnerAcceptedEvent"); + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PARTNER_ACCEPTED, + event.getPartner().getId().toString(), + null, + conv.toAPIObject(event.getPartner())); + messageService.sendMessage(message); + + activityManager.addPartnerAcceptedActivity(event.getPartner()); + } + + @EventListener + @Async + public void onPartnerRemovedEvent(PartnerRemovedEvent event) { + log.debug("onPartnerRemovedEvent"); + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PARTNER_REMOVED, + event.getPartner().getId().toString(), + null, + conv.toAPIObject(event.getPartner())); + messageService.sendMessage(message); + + activityManager.deletePartnerActivities(event.getPartner()); + } + + @EventListener + @Async + public void onPresentationRequestCompletedEvent(PresentationRequestCompletedEvent event) { + log.debug("onPresentationRequestCompletedEvent"); + // we have the partner id, but not the partner, will need to look up partner... + partnerManager.getPartnerById(event.getPartnerProof().getPartnerId()).ifPresent(p -> { + WebSocketMessageBody message = null; + if (event.getPartnerProof().getRole().equals(PresentationExchangeRole.PROVER)) { + message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_PROVED, + event.getPartnerProof().getId().toString(), + conv.toAPIObject(event.getPartnerProof()), + p); + } else { + message = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_VERIFIED, + event.getPartnerProof().getId().toString(), + conv.toAPIObject(event.getPartnerProof()), + p); + } + activityManager.completePresentationExchangeTask(event.getPartnerProof()); + messageService.sendMessage(message); + }); + } + + @EventListener + @Async + public void onPresentationRequestDeclinedEvent(PresentationRequestDeclinedEvent event) { + log.debug("onPresentationRequestDeclinedEvent"); + handlePresentationRequestEvent(event.getPartnerProof(), + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_REQUEST_DECLINED); + activityManager.declinePresentationExchangeTask(event.getPartnerProof()); + } + + @EventListener + @Async + public void onPresentationRequestDeletedEvent(PresentationRequestDeletedEvent event) { + log.debug("onPresentationRequestDeletedEvent"); + handlePresentationRequestEvent(event.getPartnerProof(), + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_REQUEST_DELETED); + activityManager.deletePresentationExchangeTask(event.getPartnerProof()); + } + + @EventListener + @Async + public void onPresentationRequestReceivedEvent(PresentationRequestReceivedEvent event) { + log.debug("onPresentationRequestReceivedEvent"); + handlePresentationRequestEvent(event.getPartnerProof(), + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_REQUEST_RECEIVED); + } + + @EventListener + @Async + public void onPresentationRequestSentEvent(PresentationRequestSentEvent event) { + log.debug("onPresentationRequestSentEvent"); + handlePresentationRequestEvent(event.getPartnerProof(), + WebSocketMessageBody.WebSocketMessageType.ON_PRESENTATION_REQUEST_SENT); + } + + @EventListener + @Async + public void onBasicMessageReceivedEvent(BasicMessageReceivedEvent event) { + log.debug("onBasicMessageReceivedEvent"); + // refactor once we have persistence of messages... + PartnerAPI partner = partnerManager.getPartnerByConnectionId(event.getMessage().getConnectionId()); + if (partner != null) { + WebSocketMessageBody message = WebSocketMessageBody.message(partner, event.getMessage()); + messageService.sendMessage(message); + } + } + + @EventListener + @Async + public void onTaskAddedEvent(TaskAddedEvent event) { + log.debug("onTaskAddedEvent"); + WebSocketMessageBody task = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.TASK_ADDED, + event.getActivity().getId().toString(), + event.getActivity(), + conv.toAPIObject(event.getActivity().getPartner())); + messageService.sendMessage(task); + } + + @EventListener + @Async + public void onTaskCompletedEvent(TaskCompletedEvent event) { + log.debug("onTaskCompletedEvent"); + WebSocketMessageBody task = WebSocketMessageBody.notificationEvent( + WebSocketMessageBody.WebSocketMessageType.TASK_COMPLETED, + event.getActivity().getId().toString(), + event.getActivity(), + conv.toAPIObject(event.getActivity().getPartner())); + messageService.sendMessage(task); + } + + private void handlePresentationRequestEvent(@NonNull PartnerProof partnerProof, + WebSocketMessageBody.WebSocketMessageType messageType) { + Optional partnerAPI = partnerManager.getPartnerById(partnerProof.getPartnerId()); + if (partnerAPI.isPresent()) { + PartnerAPI p = partnerAPI.get(); + + activityManager.addPresentationExchangeTask(partnerProof); + + // only notify if this is a task (requires manual intervention) + if (activityLogConfig.getPresentationExchangeStatesForTasks().contains(partnerProof.getState())) { + // we have the partner id, but not the partner, will need to look up partner... + WebSocketMessageBody message = WebSocketMessageBody.notificationEvent( + messageType, + partnerProof.getId().toString(), + conv.toAPIObject(partnerProof), + p); + messageService.sendMessage(message); + } + } + } + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/PartnerManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/PartnerManager.java index f10cc2abb..3818eb2fb 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/PartnerManager.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/PartnerManager.java @@ -40,7 +40,10 @@ import javax.inject.Inject; import javax.inject.Singleton; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.StreamSupport; diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/AriesEventHandler.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/AriesEventHandler.java index 1550d007a..72618e94a 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/AriesEventHandler.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/AriesEventHandler.java @@ -22,6 +22,7 @@ import org.hyperledger.aries.api.issue_credential_v1.CredentialExchangeRole; import org.hyperledger.aries.api.issue_credential_v1.CredentialExchangeState; import org.hyperledger.aries.api.issue_credential_v1.V1CredentialExchange; +import org.hyperledger.aries.api.message.BasicMessage; import org.hyperledger.aries.api.message.PingEvent; import org.hyperledger.aries.api.message.ProblemReport; import org.hyperledger.aries.api.present_proof.PresentationExchangeRecord; @@ -115,6 +116,11 @@ public void handleProblemReport(ProblemReport report) { proofMgmt.handleProblemReport(report.getThread().getThid(), report.getDescription()); } + @Override + public void handleBasicMessage(BasicMessage message) { + conMgmt.receiveMessage(message); + } + @Override public void handleRaw(String eventType, String json) { log.trace(json); diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ConnectionManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ConnectionManager.java index e9e8972b5..e3db6d5d1 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ConnectionManager.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ConnectionManager.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.micronaut.context.annotation.Value; +import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.util.CollectionUtils; import lombok.NonNull; @@ -32,15 +33,16 @@ import org.hyperledger.aries.api.connection.*; import org.hyperledger.aries.api.did_exchange.DidExchangeCreateRequestFilter; import org.hyperledger.aries.api.exception.AriesException; +import org.hyperledger.aries.api.message.BasicMessage; import org.hyperledger.aries.api.out_of_band.CreateInvitationFilter; import org.hyperledger.aries.api.present_proof.PresentProofRecordsFilter; import org.hyperledger.aries.api.present_proof.PresentationExchangeRecord; import org.hyperledger.bpa.api.exception.NetworkException; import org.hyperledger.bpa.config.BPAMessageSource; -import org.hyperledger.bpa.controller.api.WebSocketMessageBody; import org.hyperledger.bpa.controller.api.partner.CreatePartnerInvitationRequest; import org.hyperledger.bpa.impl.MessageService; import org.hyperledger.bpa.impl.activity.DidResolver; +import org.hyperledger.bpa.impl.notification.*; import org.hyperledger.bpa.impl.util.Converter; import org.hyperledger.bpa.model.Partner; import org.hyperledger.bpa.model.PartnerProof; @@ -92,6 +94,9 @@ public class ConnectionManager { @Inject BPAMessageSource.DefaultMessageSource messageSource; + @Inject + ApplicationEventPublisher eventPublisher; + /** * Creates a connection invitation to be used within a barcode * @@ -172,6 +177,12 @@ public void handleOutgoingConnectionEvent(ConnectionRecord record) { } else { partnerRepo.updateState(dbP.getId(), record.getState()); } + if (ConnectionState.REQUEST.equals(record.getState())) { + eventPublisher.publishEventAsync(PartnerAddedEvent.builder().partner(dbP).build()); + } else if (ConnectionState.RESPONSE.equals(record.getState()) || + ConnectionState.COMPLETED.equals(record.getState())) { + eventPublisher.publishEventAsync(PartnerAcceptedEvent.builder().partner(dbP).build()); + } }); } @@ -226,7 +237,11 @@ private void resolveAndSend(ConnectionRecord record, Partner p) { // only incoming connections in state request if (ConnectionState.REQUEST.equals(record.getState())) { didResolver.lookupIncoming(p); - messageService.sendMessage(WebSocketMessageBody.partnerReceived(conv.toAPIObject(p))); + if (record.isIncomingConnection()) { + eventPublisher.publishEventAsync(PartnerRequestReceivedEvent.builder().partner(p).build()); + } + } else if (ConnectionState.COMPLETED.equals(record.getState()) && record.isIncomingConnection()) { + eventPublisher.publishEventAsync(PartnerRequestCompletedEvent.builder().partner(p).build()); } } @@ -239,7 +254,8 @@ public void removeConnection(String connectionId) { log.warn("Could not delete aries connection.", e); } - partnerRepo.findByConnectionId(connectionId).ifPresent(p -> { + Optional partner = partnerRepo.findByConnectionId(connectionId); + partner.ifPresent(p -> { final List proofs = partnerProofRepo.findByPartnerId(p.getId()); if (CollectionUtils.isNotEmpty(proofs)) { partnerProofRepo.deleteAll(proofs); @@ -263,7 +279,9 @@ public void removeConnection(String connectionId) { }); myCredRepo.updateByConnectionId(connectionId, null); - + if (partner.isPresent()) { + eventPublisher.publishEventAsync(PartnerRemovedEvent.builder().partner(partner.get()).build()); + } } catch (IOException e) { log.error("Could not delete connection: {}", connectionId, e); } @@ -280,6 +298,10 @@ public void sendMessage(String connectionId, String content) { } } + public void receiveMessage(BasicMessage message) { + eventPublisher.publishEventAsync(BasicMessageReceivedEvent.builder().message(message).build()); + } + private InvitationRecord createOOBInvitation(@Nullable String alias) throws IOException { return ac.outOfBandCreateInvitation( InvitationCreateRequest.builder() diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/CredentialManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/CredentialManager.java index 43d22459f..e43a84ad9 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/CredentialManager.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/CredentialManager.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.micronaut.context.annotation.Value; +import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.Nullable; import lombok.NonNull; import lombok.Setter; @@ -39,11 +40,11 @@ import org.hyperledger.bpa.api.aries.ProfileVC; import org.hyperledger.bpa.api.exception.NetworkException; import org.hyperledger.bpa.api.exception.PartnerException; -import org.hyperledger.bpa.controller.api.WebSocketMessageBody; import org.hyperledger.bpa.impl.MessageService; import org.hyperledger.bpa.impl.activity.LabelStrategy; import org.hyperledger.bpa.impl.activity.VPManager; import org.hyperledger.bpa.impl.aries.config.SchemaService; +import org.hyperledger.bpa.impl.notification.CredentialAddedEvent; import org.hyperledger.bpa.impl.util.AriesStringUtil; import org.hyperledger.bpa.impl.util.Converter; import org.hyperledger.bpa.model.MyCredential; @@ -103,6 +104,9 @@ public class CredentialManager { @Inject LabelStrategy labelStrategy; + @Inject + ApplicationEventPublisher eventPublisher; + // request credential from issuer (partner) public void sendCredentialRequest(@NonNull UUID partnerId, @NonNull UUID myDocId) { final Optional dbPartner = partnerRepo.findById(partnerId); @@ -169,7 +173,11 @@ public void handleCredentialAcked(V1CredentialExchange credEx) { .setIssuedAt(Instant.now()) .setLabel(label); MyCredential updated = credRepo.update(cred); - messageService.sendMessage(WebSocketMessageBody.credentialReceived(buildAriesCredential(updated))); + AriesCredential ariesCredential = buildAriesCredential(updated); + eventPublisher.publishEventAsync(CredentialAddedEvent.builder() + .credential(ariesCredential) + .credentialExchange(credEx) + .build()); }, () -> log.error("Received credential without matching thread id, credential is not stored.")); } @@ -215,7 +223,7 @@ private AriesCredential buildAriesCredential(MyCredential dbCred) { /** * Updates the credentials label - * + * * @param id the credential id * @param label the credentials label * @return the updated credential if found diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofEventHandler.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofEventHandler.java index 39d5fdc9c..d6eaade30 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofEventHandler.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofEventHandler.java @@ -17,6 +17,7 @@ */ package org.hyperledger.bpa.impl.aries; +import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.util.CollectionUtils; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; @@ -24,8 +25,11 @@ import org.hyperledger.aries.api.present_proof.PresentationExchangeRecord; import org.hyperledger.aries.api.present_proof.PresentationExchangeRole; import org.hyperledger.aries.api.present_proof.PresentationExchangeState; -import org.hyperledger.bpa.controller.api.WebSocketMessageBody; import org.hyperledger.bpa.impl.MessageService; +import org.hyperledger.bpa.impl.notification.PresentationRequestCompletedEvent; +import org.hyperledger.bpa.impl.notification.PresentationRequestDeclinedEvent; +import org.hyperledger.bpa.impl.notification.PresentationRequestReceivedEvent; +import org.hyperledger.bpa.impl.util.Converter; import org.hyperledger.bpa.model.PartnerProof; import org.hyperledger.bpa.repository.PartnerProofRepository; import org.hyperledger.bpa.repository.PartnerRepository; @@ -50,6 +54,12 @@ public class ProofEventHandler { @Inject MessageService messageService; + @Inject + Converter conv; + + @Inject + ApplicationEventPublisher eventPublisher; + void dispatch(PresentationExchangeRecord proof) { if (proof.isVerified() && PresentationExchangeRole.VERIFIER.equals(proof.getRole()) || PresentationExchangeState.PRESENTATION_ACKED.equals(proof.getState()) @@ -65,7 +75,7 @@ void dispatch(PresentationExchangeRecord proof) { /** * Default proof event handler that either stores or updates partner proofs - * + * * @param proof {@link PresentationExchangeRecord} */ private void handleAll(PresentationExchangeRecord proof) { @@ -78,6 +88,8 @@ private void handleAll(PresentationExchangeRecord proof) { } if (proof.getErrorMsg() != null) { pProofRepo.updateProblemReport(pp.getId(), proof.getErrorMsg()); + eventPublisher.publishEventAsync( + PresentationRequestDeclinedEvent.builder().partnerProof(pp).build()); } }, () -> pProofRepo.save(defaultProof(p.getId(), proof))), @@ -87,21 +99,16 @@ private void handleAll(PresentationExchangeRecord proof) { /** * Handles all events that are either acked or verified connectionless proofs * are currently not handled - * + * * @param proof {@link PresentationExchangeRecord} */ private void handleAckedOrVerified(PresentationExchangeRecord proof) { pProofRepo.findByPresentationExchangeId(proof.getPresentationExchangeId()).ifPresent(pp -> { if (CollectionUtils.isNotEmpty(proof.getIdentifiers())) { PartnerProof savedProof = proofManager.handleAckedOrVerifiedProofEvent(proof, pp); - - WebSocketMessageBody.WebSocketMessageState state = PresentationExchangeRole.VERIFIER - .equals(proof.getRole()) ? WebSocketMessageBody.WebSocketMessageState.RECEIVED - : WebSocketMessageBody.WebSocketMessageState.SENT; - proofManager.sendMessage( - state, - WebSocketMessageBody.WebSocketMessageType.PROOF, - savedProof); + eventPublisher.publishEventAsync(PresentationRequestCompletedEvent.builder() + .partnerProof(savedProof) + .build()); } else { log.warn("Proof does not contain any identifiers event will not be persisted"); } @@ -110,7 +117,7 @@ private void handleAckedOrVerified(PresentationExchangeRecord proof) { /** * Handles all proof request - * + * * @param proof {@link PresentationExchangeRecord} */ private void handleProofRequest(@NonNull PresentationExchangeRecord proof) { @@ -135,13 +142,17 @@ private void handleProofRequest(@NonNull PresentationExchangeRecord proof) { final PartnerProof pp = defaultProof(p.getId(), proof) .setProofRequest(proof.getPresentationRequest()); pProofRepo.save(pp); + eventPublisher.publishEventAsync(PresentationRequestReceivedEvent.builder() + .partnerProof(pp) + .build()); + })); } /** * Handle present proof problem report message - * + * * @param threadId the thread id of the exchange * @param description the problem description */ @@ -151,7 +162,7 @@ void handleProblemReport(@NonNull String threadId, @NonNull String description) /** * Build db proof representation with all mandatory fields that are required - * + * * @param partnerId the partner id * @param proof {link PresentationExchangeRecord} * @return {@link PartnerProof} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofManager.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofManager.java index 1d59b69ee..126d16881 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofManager.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/aries/ProofManager.java @@ -17,8 +17,8 @@ */ package org.hyperledger.bpa.impl.aries; -import com.fasterxml.jackson.databind.JsonNode; import io.micronaut.context.annotation.Value; +import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.util.CollectionUtils; import io.micronaut.core.util.StringUtils; @@ -35,11 +35,12 @@ import org.hyperledger.bpa.api.exception.PartnerException; import org.hyperledger.bpa.api.exception.PresentationConstructionException; import org.hyperledger.bpa.api.exception.WrongApiUsageException; -import org.hyperledger.bpa.controller.api.WebSocketMessageBody; import org.hyperledger.bpa.controller.api.partner.RequestProofRequest; import org.hyperledger.bpa.impl.MessageService; import org.hyperledger.bpa.impl.activity.DidResolver; import org.hyperledger.bpa.impl.aries.config.SchemaService; +import org.hyperledger.bpa.impl.notification.PresentationRequestDeletedEvent; +import org.hyperledger.bpa.impl.notification.PresentationRequestSentEvent; import org.hyperledger.bpa.impl.util.AriesStringUtil; import org.hyperledger.bpa.impl.util.Converter; import org.hyperledger.bpa.impl.util.TimeUtil; @@ -91,6 +92,9 @@ public class ProofManager { @Inject MessageService messageService; + @Inject + ApplicationEventPublisher eventPublisher; + // request proof from partner public void sendPresentProofRequest(@NonNull UUID partnerId, @NonNull RequestProofRequest req) { try { @@ -116,6 +120,10 @@ public void sendPresentProofRequest(@NonNull UUID partnerId, @NonNull RequestPro .issuer(req.getFirstIssuerDid()) .build(); pProofRepo.save(pp); + + eventPublisher.publishEventAsync(PresentationRequestSentEvent.builder() + .partnerProof(pp) + .build()); }); } else { throw new PartnerException("Could not find any schema on the ledger for id: " @@ -131,6 +139,10 @@ public void sendPresentProofRequest(@NonNull UUID partnerId, @NonNull RequestPro .role(exchange.getRole()) .build(); pProofRepo.save(pp); + + eventPublisher.publishEventAsync(PresentationRequestSentEvent.builder() + .partnerProof(pp) + .build()); }); } } else { @@ -149,6 +161,8 @@ public void declinePresentProofRequest(@NotNull PartnerProof proofEx, String exp try { sendPresentProofProblemReport(proofEx.getPresentationExchangeId(), explainString); deletePartnerProof(proofEx.getId()); + eventPublisher + .publishEventAsync(PresentationRequestDeletedEvent.builder().partnerProof(proofEx).build()); } catch (IOException e) { throw new NetworkException(ACA_PY_ERROR_MSG, e); } catch (AriesException e) { @@ -241,6 +255,10 @@ public void sendProofProposal(@NonNull UUID partnerId, @NonNull UUID myCredentia .issuer(resolveIssuer(cred.getCredentialDefinitionId())) .build(); pProofRepo.save(pp); + + eventPublisher.publishEventAsync(PresentationRequestSentEvent.builder() + .partnerProof(pp) + .build()); }); } catch (IOException e) { @@ -251,7 +269,7 @@ public void sendProofProposal(@NonNull UUID partnerId, @NonNull UUID myCredentia public List listPartnerProofs(@NonNull UUID partnerId) { List result = new ArrayList<>(); - pProofRepo.findByPartnerIdOrderByRole(partnerId).forEach(p -> result.add(toApiProof(p))); + pProofRepo.findByPartnerIdOrderByRole(partnerId).forEach(p -> result.add(conv.toAPIObject(p))); return result; } @@ -259,7 +277,7 @@ public Optional getPartnerProofById(@NonNull UUID id) { Optional result = Optional.empty(); final Optional proof = pProofRepo.findById(id); if (proof.isPresent()) { - result = Optional.of(toApiProof(proof.get())); + result = Optional.of(conv.toAPIObject(proof.get())); } return result; } @@ -281,13 +299,6 @@ public void deletePartnerProof(@NonNull UUID id) { }); } - void sendMessage( - @NonNull WebSocketMessageBody.WebSocketMessageState state, - @NonNull WebSocketMessageBody.WebSocketMessageType type, - @NonNull PartnerProof pp) { - messageService.sendMessage(WebSocketMessageBody.proof(state, type, toApiProof(pp))); - } - private @Nullable String resolveIssuer(String credDefId) { String issuer = null; if (StringUtils.isNotEmpty(credDefId)) { @@ -296,15 +307,6 @@ void sendMessage( return issuer; } - private AriesProofExchange toApiProof(@NonNull PartnerProof p) { - AriesProofExchange proof = AriesProofExchange.from(p, - p.getProof() != null ? conv.fromMap(p.getProof(), JsonNode.class) : null); - if (StringUtils.isNotEmpty(p.getSchemaId())) { - proof.setTypeLabel(schemaService.getSchemaLabel(p.getSchemaId())); - } - return proof; - } - private void sendPresentProofProblemReport(@NonNull String PresentationExchangeId, @NonNull String problemString) throws IOException { V10PresentationProblemReportRequest request = V10PresentationProblemReportRequest.builder() diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/BasicMessageReceivedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/BasicMessageReceivedEvent.java new file mode 100644 index 000000000..2f1eb710c --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/BasicMessageReceivedEvent.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.aries.api.message.BasicMessage; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class BasicMessageReceivedEvent { + private BasicMessage message; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/CredentialAddedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/CredentialAddedEvent.java new file mode 100644 index 000000000..ec0bb2773 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/CredentialAddedEvent.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.aries.api.issue_credential_v1.V1CredentialExchange; +import org.hyperledger.bpa.api.aries.AriesCredential; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class CredentialAddedEvent { + + private AriesCredential credential; + private V1CredentialExchange credentialExchange; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAcceptedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAcceptedEvent.java new file mode 100644 index 000000000..b4fa7c650 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAcceptedEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Partner; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PartnerAcceptedEvent { + + private Partner partner; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAddedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAddedEvent.java new file mode 100644 index 000000000..a1be0e1ad --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerAddedEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Partner; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PartnerAddedEvent { + + private Partner partner; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRemovedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRemovedEvent.java new file mode 100644 index 000000000..e48e12a13 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRemovedEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Partner; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PartnerRemovedEvent { + + private Partner partner; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestCompletedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestCompletedEvent.java new file mode 100644 index 000000000..c8116d02e --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestCompletedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Partner; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PartnerRequestCompletedEvent { + + private Partner partner; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestReceivedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestReceivedEvent.java new file mode 100644 index 000000000..e695e51fc --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PartnerRequestReceivedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Partner; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PartnerRequestReceivedEvent { + + private Partner partner; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestCompletedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestCompletedEvent.java new file mode 100644 index 000000000..b5614068e --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestCompletedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.PartnerProof; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PresentationRequestCompletedEvent { + + private PartnerProof partnerProof; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeclinedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeclinedEvent.java new file mode 100644 index 000000000..022db9a76 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeclinedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.PartnerProof; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PresentationRequestDeclinedEvent { + + private PartnerProof partnerProof; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeletedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeletedEvent.java new file mode 100644 index 000000000..5dcc7361f --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestDeletedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.PartnerProof; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PresentationRequestDeletedEvent { + + private PartnerProof partnerProof; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestReceivedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestReceivedEvent.java new file mode 100644 index 000000000..1d919d5f8 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestReceivedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.PartnerProof; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PresentationRequestReceivedEvent { + + private PartnerProof partnerProof; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestSentEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestSentEvent.java new file mode 100644 index 000000000..0309ffcbd --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/PresentationRequestSentEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.PartnerProof; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class PresentationRequestSentEvent { + + private PartnerProof partnerProof; + +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskAddedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskAddedEvent.java new file mode 100644 index 000000000..4c4a44d15 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskAddedEvent.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Activity; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class TaskAddedEvent { + private Activity activity; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskCompletedEvent.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskCompletedEvent.java new file mode 100644 index 000000000..e6a4d7702 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/notification/TaskCompletedEvent.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.impl.notification; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.model.Activity; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class TaskCompletedEvent { + private Activity activity; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/util/Converter.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/util/Converter.java index a0dddf02d..bfd4e7085 100644 --- a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/util/Converter.java +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/impl/util/Converter.java @@ -40,11 +40,14 @@ import org.hyperledger.bpa.api.MyDocumentAPI; import org.hyperledger.bpa.api.PartnerAPI; import org.hyperledger.bpa.api.PartnerAPI.PartnerCredential; +import org.hyperledger.bpa.api.aries.AriesProofExchange; import org.hyperledger.bpa.impl.aries.config.SchemaService; import org.hyperledger.bpa.model.MyDocument; import org.hyperledger.bpa.model.Partner; import io.micronaut.core.annotation.Nullable; +import org.hyperledger.bpa.model.PartnerProof; + import javax.inject.Inject; import javax.inject.Singleton; import javax.validation.constraints.NotNull; @@ -193,6 +196,15 @@ public Optional writeValueAsString(Object value) { return Optional.empty(); } + public AriesProofExchange toAPIObject(@NonNull PartnerProof p) { + AriesProofExchange proof = AriesProofExchange.from(p, + p.getProof() != null ? this.fromMap(p.getProof(), JsonNode.class) : null); + if (io.micronaut.core.util.StringUtils.isNotEmpty(p.getSchemaId())) { + proof.setTypeLabel(schemaService.getSchemaLabel(p.getSchemaId())); + } + return proof; + } + private String resolveTypeLabel(@NonNull CredentialType type, @Nullable String schemaId) { String result = null; if (CredentialType.SCHEMA_BASED.equals(type) diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/model/Activity.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/model/Activity.java new file mode 100644 index 000000000..08d0d0bf8 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/model/Activity.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.model; + +import io.micronaut.data.annotation.AutoPopulated; +import io.micronaut.data.annotation.DateCreated; +import io.micronaut.data.annotation.DateUpdated; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hyperledger.bpa.controller.api.activity.ActivityRole; +import org.hyperledger.bpa.controller.api.activity.ActivityState; +import org.hyperledger.bpa.controller.api.activity.ActivityType; + +import javax.persistence.*; +import java.time.Instant; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Entity +@Table(name = "activity") +public class Activity { + + @Id + @AutoPopulated + private UUID id; + + private UUID linkId; + + @OneToOne + private Partner partner; + + @Enumerated(EnumType.STRING) + private ActivityType type; + + @Enumerated(EnumType.STRING) + private ActivityRole role; + + @Enumerated(EnumType.STRING) + private ActivityState state; + + private boolean completed; + + @DateCreated + private Instant createdAt; + @DateUpdated + private Instant updatedAt; +} diff --git a/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/repository/ActivityRepository.java b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/repository/ActivityRepository.java new file mode 100644 index 000000000..2be37e0d7 --- /dev/null +++ b/backend/business-partner-agent/src/main/java/org/hyperledger/bpa/repository/ActivityRepository.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020-2021 - for information on the respective copyright owner + * see the NOTICE file and/or the repository at + * https://github.com/hyperledger-labs/business-partner-agent + * + * 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. + */ +package org.hyperledger.bpa.repository; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.data.annotation.Join; +import io.micronaut.data.jdbc.annotation.JdbcRepository; +import io.micronaut.data.model.query.builder.sql.Dialect; +import io.micronaut.data.repository.CrudRepository; +import org.hyperledger.bpa.controller.api.activity.ActivityRole; +import org.hyperledger.bpa.controller.api.activity.ActivityType; +import org.hyperledger.bpa.model.Activity; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@JdbcRepository(dialect = Dialect.POSTGRES) +public interface ActivityRepository extends CrudRepository { + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByPartnerId(@NonNull UUID partnerId); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByLinkId(@NonNull UUID linkId); + + Optional findByLinkIdAndTypeAndRole(@NonNull UUID linkId, + @NonNull ActivityType type, + @NonNull ActivityRole role); + + void updateByLinkIdAndTypeAndRole(@NonNull UUID linkId, + @NonNull ActivityType type, + @NonNull ActivityRole role, + boolean completed); + + void deleteByLinkIdAndType(@NonNull UUID linkId, + @NonNull ActivityType type); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List listOrderByUpdatedAtDesc(); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByTypeOrderByUpdatedAt(@NonNull ActivityType type); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByCompletedFalseOrderByUpdatedAtDesc(); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByTypeAndCompletedFalseOrderByUpdatedAtDesc(@NonNull ActivityType type); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByCompletedTrueOrderByUpdatedAtDesc(); + + @Join(value = "partner", type = Join.Type.LEFT_FETCH) + List findByTypeAndCompletedTrueOrderByUpdatedAtDesc(@NonNull ActivityType type); + + void deleteByPartnerId(@NonNull UUID partnerId); +} diff --git a/backend/business-partner-agent/src/main/resources/databasemigrations/V1.17__add-activity-table.sql b/backend/business-partner-agent/src/main/resources/databasemigrations/V1.17__add-activity-table.sql new file mode 100644 index 000000000..9ffab6097 --- /dev/null +++ b/backend/business-partner-agent/src/main/resources/databasemigrations/V1.17__add-activity-table.sql @@ -0,0 +1,11 @@ +CREATE TABLE activity ( + id uuid PRIMARY KEY, + partner_id uuid NOT NULL, + link_id uuid NOT NULL, + type character varying(255), + role character varying(255), + state character varying(255), + completed boolean NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone +); diff --git a/backend/business-partner-agent/src/main/resources/log4j2.xml b/backend/business-partner-agent/src/main/resources/log4j2.xml index a42304076..fdfe3ca7f 100644 --- a/backend/business-partner-agent/src/main/resources/log4j2.xml +++ b/backend/business-partner-agent/src/main/resources/log4j2.xml @@ -6,7 +6,7 @@ - + diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 2e06f5919..014b67839 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -67,8 +67,8 @@ - $vuetify.icons.partners + + $vuetify.icons.partners + {{ $t("nav.partners") }} @@ -223,8 +233,8 @@ + @@ -77,10 +83,11 @@ import {ActivityRoles, ActivityStates, ActivityTypes} from "@/constants"; import VBpaButton from "@/components/BpaButton"; import activitiesService from "@/services/activitiesService"; + import NewMessageIcon from "@/components/NewMessageIcon"; export default { name: "ActivityList", - components: { VBpaButton }, + components: { VBpaButton, NewMessageIcon }, props: { activities: { type: Boolean, @@ -93,6 +100,12 @@ headers: { type: Array, default: () => [ + { + text: '', + value: 'indicator', + sortable: false, + filterable: false + }, { text: "Type", value: "type", @@ -164,6 +177,9 @@ }); }, openItem(item) { + // if we click on it, mark it seen... + this.$store.commit("taskNotificationSeen", {id: item.id}); + if (item.type === ActivityTypes.CONNECTION_REQUEST.value) { this.$router.push({ name: "Partner", @@ -171,15 +187,48 @@ id: item.linkId, }, }); - } - // TODO: change this to go to the Proof/Presentation details screen when it exists... - if (item.type === ActivityTypes.PRESENTATION_EXCHANGE.value) { - this.$router.push({ + } else if (item.type === ActivityTypes.PRESENTATION_EXCHANGE.value) { + // by default, just go to the partner screen... + let route = { name: "Partner", params: { - id: item.linkId, + id: item.partner.id, }, - }); + }; + if (item.role === ActivityRoles.PRESENTATION_EXCHANGE_PROVER.value) { + // if role prover and received -> presentation-request/6a693ed0-8978-4ff7-a15a-343be7b4cdb4/details + // if prover and accepted -> partners/a0ebe43f-8fdd-4ab0-a3d5-07d4d8ca42f9/presentation/6a693ed0-8978-4ff7-a15a-343be7b4cdb4 + if (item.state === ActivityStates.PRESENTATION_EXCHANGE_RECEIVED.value) { + route = { + name: "PresentationRequestDetails", + params: { + id: item.linkId, + }, + }; + } else if (item.state === ActivityStates.PRESENTATION_EXCHANGE_ACCEPTED.value) { + route = { + name: "Presentation", + params: { + id: item.partner.id, + presentationId: item.linkId, + }, + }; + } + } else if (item.role === ActivityRoles.PRESENTATION_EXCHANGE_VERIFIER.value) { + // if verifier and sent -> nothing go to partner + // if verifier and declined -> nothing go to partner + // if verifier and accepted -> partners/a0ebe43f-8fdd-4ab0-a3d5-07d4d8ca42f9/presentation/80311f0c-2738-4cb4-9d0c-3cc4d81742aa + if (item.state === ActivityStates.PRESENTATION_EXCHANGE_ACCEPTED.value) { + route = { + name: "Presentation", + params: { + id: item.partner.id, + presentationId: item.linkId, + }, + }; + } + } + this.$router.push(route); } }, diff --git a/frontend/src/components/CredExList.vue b/frontend/src/components/CredExList.vue index fbd7350eb..e0b5010fe 100644 --- a/frontend/src/components/CredExList.vue +++ b/frontend/src/components/CredExList.vue @@ -18,6 +18,12 @@ single-select @click:row="openItem" > +