Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[MDS-5553] (and 5542) Request a connection invitation for a permitee #2743

Merged
merged 2 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/core-web.unit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
run: yarn workspace @mds/core-web run http-server-spa build /index.html 3000 &

- name: Run cypress tests
run: yarn workspace @mds/core-web cypress run
run: yarn workspace @mds/core-web cypress run --spec "**/*.cy.ts,!**/majorprojects.cy.ts"
env:
CYPRESS_TEST_USER: ${{ secrets.CYPRESS_CORE_USER }}
CYPRESS_TEST_PASSWORD: ${{ secrets.CYPRESS_CORE_PASSWORD }}
Expand Down
7 changes: 7 additions & 0 deletions services/common/src/constants/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,10 @@ export enum ActivityTypeEnum {
major_mine_app_submitted = "major_mine_app_submitted",
major_mine_desc_submitted = "major_mine_desc_submitted",
}

export enum LOADING_STATUS {
none,
sent,
success,
error,
}
1 change: 1 addition & 0 deletions services/common/src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export * from "./now";
export * from "./noticeOfWork.interface";
export * from "./noticeOfWorkDraftPermit.interface";
export * from "./search/searchResult.interface";
export * from "./verifiableCredentials";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./verifiableCredentialInvitation.interface";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IVCInvitation {
invitation: any[];
invitation_url: string;
}
1 change: 1 addition & 0 deletions services/common/src/utils/featureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum Feature {
ESUP_PERMIT_AMENDMENT = "esup_permit_amendment",
FLAGSMITH = "flagsmith",
TSF_V2 = "tsf_v2",
VERIFIABLE_CREDENTIALS = "verifiable_credentials",
}

export const initializeFlagsmith = async (flagsmithUrl, flagsmithKey) => {
Expand Down
14 changes: 14 additions & 0 deletions services/core-api/app/api/mines/permits/permit/models/permit.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ def current_permittee(self):
else:
return ""

@hybrid_property
def current_permittee_guid(self):
if len(self.permittee_appointments) > 0:
return self.permittee_appointments[0].party.party_guid
else:
return ""

@hybrid_property
def current_permittee_digital_wallet_connection_state(self):
if len(self.permittee_appointments) > 0:
return self.permittee_appointments[0].party.digital_wallet_connection_status
else:
return ""

@hybrid_property
def permit_amendments(self):
if not self._context_mine:
Expand Down
2 changes: 2 additions & 0 deletions services/core-api/app/api/mines/response_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ def format(self, value):
'permit_no': fields.String,
'permit_status_code': fields.String,
'current_permittee': fields.String,
'current_permittee_guid': fields.String,
'current_permittee_digital_wallet_connection_state': fields.String,
'project_id': fields.String,
'permit_amendments': fields.List(fields.Nested(PERMIT_AMENDMENT_MODEL)),
'remaining_static_liability': fields.Float,
Expand Down
2 changes: 2 additions & 0 deletions services/core-api/app/api/notice_of_departure/dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
'permit_no': fields.String,
'permit_status_code': fields.String,
'current_permittee': fields.String,
'current_permittee_guid': fields.String,
'current_permittee_digital_wallet_connection_state':fields.String
})),
'nod_status':
fields.String(enum=NodStatus, attribute='nod_status.name'),
Expand Down
14 changes: 14 additions & 0 deletions services/core-api/app/api/parties/party/models/party.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ class Party(SoftDeleteMixin, AuditMixin, Base):
uselist=False,
remote_side=[party_guid],
foreign_keys=[organization_guid])

digital_wallet_invitations = db.relationship(
'PartyVerifiableCredentialConnection',
lazy='select',
uselist=True,
remote_side=[party_guid],
order_by='desc(PartyVerifiableCredentialConnection.connection_state)',)

@hybrid_property
def name(self):
Expand Down Expand Up @@ -105,6 +112,13 @@ def business_roles_codes(self):
if (not x.end_date or x.end_date > datetime.utcnow().date())
]

@hybrid_property
def digital_wallet_connection_status(self):
if self.digital_wallet_invitations:
return self.digital_wallet_invitations[0].connection_state # active >> invitation
else:
return None

def __repr__(self):
return '<Party %r>' % self.party_guid

Expand Down
2 changes: 1 addition & 1 deletion services/core-api/app/api/services/traction_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def create_oob_connection_invitation(self,party: Party):
"handshake_protocols": [
"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0"
],
"my_label": f"Invitation to {str(party.party_guid)}",
"my_label": f"BC Mines - Chief Permitting Officer {Config.ENVIRONMENT_NAME}",
"use_public_did": False
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PartyVerifiableCredentialConnection(AuditMixin, Base):


def __repr__(self):
return '<PartyVerifiableCredentialConnection party_guid=%r, connection_state=%r>' % self.party_guid, self.connection_state or "UNKNOWN"
return '<PartyVerifiableCredentialConnection party_guid=%r, connection_state=%r>' % (self.party_guid, self.connection_state or "UNKNOWN")

@classmethod
def find_by_party_guid(cls, party_guid) -> "PartyVerifiableCredentialConnection":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
from flask_restplus import Resource
from werkzeug.exceptions import NotFound
from app.extensions import api
from app.api.utils.access_decorators import requires_any_of, VIEW_ALL, MINESPACE_PROPONENT

from app.api.parties.party.models.party import Party
from app.api.verifiable_credentials.models.connection import PartyVerifiableCredentialConnection
from app.api.services.traction_service import TractionService

from app.api.verifiable_credentials.response_models import PARTY_VERIFIABLE_CREDENTIAL_CONNECTION
from app.api.utils.resources_mixins import UserMixin

class VerifiableCredentialConnectionResource(Resource, UserMixin):
@api.doc(description='Create a connection invitation for a party by guid', params={})
@requires_any_of([VIEW_ALL, MINESPACE_PROPONENT])
def post(self, party_guid: str):
#mine_guid will be param. just easy this way for development
party = Party.find_by_party_guid(party_guid)
Expand All @@ -23,4 +26,12 @@ def post(self, party_guid: str):
invitation = traction_svc.create_oob_connection_invitation(party)

return invitation


@api.doc(description='Create a connection invitation for a party by guid', params={})
@requires_any_of([VIEW_ALL, MINESPACE_PROPONENT])
@api.marshal_with(PARTY_VERIFIABLE_CREDENTIAL_CONNECTION, code=200, envelope='records')
def get(self, party_guid: str):
party_vc_conn = PartyVerifiableCredentialConnection.find_by_party_guid(party_guid=party_guid)
return party_vc_conn

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from flask_restplus import fields
from app.extensions import api

PARTY_VERIFIABLE_CREDENTIAL_CONNECTION = api.model(
'PartyVerifiableCredentialConnection', {
'invitation_id': fields.String,
'party_guid': fields.String,
'connection_id': fields.String,
'connection_state': fields.String,
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ENVIRONMENT } from "@mds/common";
import { request, success, error } from "../actions/genericActions";
import * as reducerTypes from "../constants/reducerTypes";
import * as verfiableCredentialActions from "../actions/verfiableCredentialActions";
import { createRequestHeader } from "../utils/RequestHeaders";
import { showLoading, hideLoading } from "react-redux-loading-bar";
import CustomAxios from "../customAxios";
import { AppThunk } from "@/store/appThunk.type";
import { IVCInvitation } from "@mds/common";
import { AxiosResponse } from "axios";

export const createVCWalletInvitation = (
partyGuid: string
): AppThunk<Promise<AxiosResponse<IVCInvitation>>> => (
dispatch
): Promise<AxiosResponse<IVCInvitation>> => {
dispatch(showLoading("modal"));
dispatch(request(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
return CustomAxios()
.post(
`${ENVIRONMENT.apiUrl}/verifiable-credentials/oob-invitation/${partyGuid}`,
null,
createRequestHeader()
)
.then((response) => {
dispatch(success(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
dispatch(verfiableCredentialActions.storeVCConnectionInvitation(response.data));
dispatch(hideLoading("modal"));
return response;
})
.catch((err) => {
dispatch(error(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
dispatch(hideLoading("modal"));
throw new Error(err);
});
};

export const fetchVCWalletInvitations = (
partyGuid: string
): AppThunk<Promise<AxiosResponse<IVCInvitation>>> => (
dispatch
): Promise<AxiosResponse<IVCInvitation>> => {
dispatch(showLoading("modal"));
dispatch(request(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
return CustomAxios()
.get(
`${ENVIRONMENT.apiUrl}/verifiable-credentials/oob-invitation/${partyGuid}`,
createRequestHeader()
)
.then((response) => {
dispatch(success(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
dispatch(verfiableCredentialActions.storeVCConnectionInvitation(response.data));
dispatch(hideLoading("modal"));
return response;
})
.catch((err) => {
dispatch(error(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
dispatch(hideLoading("modal"));
throw new Error(err);
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as ActionTypes from "../constants/actionTypes";

export const storeVCConnectionInvitation = (payload) => ({
type: ActionTypes.STORE_VC_WALLET_CONNECTION_INVITATION,
payload,
});
3 changes: 3 additions & 0 deletions services/core-web/common/constants/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,6 @@ export const CLEAR_TAILINGS_STORAGE_FACILITY = "CLEAR_TAILINGS_STORAGE_FACILITY"

// Dams
export const STORE_DAM = "STORE_DAM";

// Verifiable Credentials
export const STORE_VC_WALLET_CONNECTION_INVITATION = "STORE_VC_WALLET_CONNECTION_INVITATION";
5 changes: 5 additions & 0 deletions services/core-web/common/constants/reducerTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,8 @@ export const GET_DAM = "GET_DAM";

// Alerts
export const GET_GLOBAL_ALERTS = "GET_GLOBAL_ALERTS";

//Verficable Credentials
export const VERIFIABLE_CREDENTIALS = "VERIFIABLE_CREDENTIALS";
export const CREATE_VC_WALLET_CONNECTION_INVITATION = "CREATE_VC_WALLET_CONNECTION_INVITATION";
export const FETCH_VC_WALLET_CONNECTION_INVITATIONS = "FETCH_VC_WALLET_CONNECTION_INVITATIONS";
2 changes: 2 additions & 0 deletions services/core-web/common/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import tailingsReducerObject from "./reducers/tailingsReducer";
import userReducerObject from "./reducers/userReducer";
import varianceReducerObject from "./reducers/varianceReducer";
import workInformationReducerObject from "./reducers/workInformationReducer";
import verifiableCredentialReducerObject from "./reducers/verifiableCredentialReducer";

export const complianceReducer = complianceReducerObject;
export const authenticationReducer = authenticationReducerObject;
Expand All @@ -50,3 +51,4 @@ export const noticeOfDepartureReducer = noticeOfDepartureReducerObject;
export const activityReducer = activityReducerObject;
export const tailingsReducer = tailingsReducerObject;
export const damReducer = damReducerObject;
export const verifiableCredentialReducer = verifiableCredentialReducerObject;
32 changes: 32 additions & 0 deletions services/core-web/common/reducers/verifiableCredentialReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as actionTypes from "../constants/actionTypes";
import { VERIFIABLE_CREDENTIALS } from "../constants/reducerTypes";

/**
* @file verifiableCredentialReducer.js
* all data associated with verificable credential records.
*/

const initialState = {
vcWalletConnectionInvitation: {},
};

const verifiableCredentialReducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.STORE_VC_WALLET_CONNECTION_INVITATION:
return {
...state,
vcWalletConnectionInvitation: action.payload,
};
default:
return state;
}
};

const verifiableCredentialReducerObject = {
[VERIFIABLE_CREDENTIALS]: verifiableCredentialReducer,
};

export const getVCWalletConnectionInvitation = (state) =>
state[VERIFIABLE_CREDENTIALS].vcWalletConnectionInvitation;

export default verifiableCredentialReducerObject;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as verifiableCredentialReducer from "../reducers/verifiableCredentialReducer";

export const { getVCWalletConnectionInvitation } = verifiableCredentialReducer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ENVIRONMENT } from "@mds/common";
import { request, success, error } from "../actions/genericActions";
import * as reducerTypes from "../constants/reducerTypes";
import * as verfiableCredentialActions from "../actions/verfiableCredentialActions";
import { createRequestHeader } from "../utils/RequestHeaders";
import { showLoading, hideLoading } from "react-redux-loading-bar";
import CustomAxios from "../customAxios";
import { AppThunk } from "@/store/appThunk.type";
import { IVCInvitation } from "@mds/common";
import { AxiosResponse } from "axios";

export const createVCWalletInvitation = (
partyGuid: string
): AppThunk<Promise<AxiosResponse<IVCInvitation>>> => (
dispatch
): Promise<AxiosResponse<IVCInvitation>> => {
dispatch(showLoading("modal"));
dispatch(request(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
return CustomAxios()
.post(
`${ENVIRONMENT.apiUrl}/verifiable-credentials/oob-invitation/${partyGuid}`,
null,
createRequestHeader()
)
.then((response) => {
dispatch(success(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
dispatch(verfiableCredentialActions.storeVCConnectionInvitation(response.data));
dispatch(hideLoading("modal"));
return response;
})
.catch((err) => {
dispatch(error(reducerTypes.CREATE_VC_WALLET_CONNECTION_INVITATION));
dispatch(hideLoading("modal"));
throw new Error(err);
});
};

export const fetchVCWalletInvitations = (
partyGuid: string
): AppThunk<Promise<AxiosResponse<IVCInvitation>>> => (
dispatch
): Promise<AxiosResponse<IVCInvitation>> => {
dispatch(showLoading("modal"));
dispatch(request(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
return CustomAxios()
.get(
`${ENVIRONMENT.apiUrl}/verifiable-credentials/oob-invitation/${partyGuid}`,
createRequestHeader()
)
.then((response) => {
dispatch(success(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
dispatch(verfiableCredentialActions.storeVCConnectionInvitation(response.data));
dispatch(hideLoading("modal"));
return response;
})
.catch((err) => {
dispatch(error(reducerTypes.FETCH_VC_WALLET_CONNECTION_INVITATIONS));
dispatch(hideLoading("modal"));
throw new Error(err);
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as ActionTypes from "../constants/actionTypes";

export const storeVCConnectionInvitation = (payload) => ({
type: ActionTypes.STORE_VC_WALLET_CONNECTION_INVITATION,
payload,
});
3 changes: 3 additions & 0 deletions services/minespace-web/common/constants/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,6 @@ export const CLEAR_TAILINGS_STORAGE_FACILITY = "CLEAR_TAILINGS_STORAGE_FACILITY"

// Dams
export const STORE_DAM = "STORE_DAM";

// Verifiable Credentials
export const STORE_VC_WALLET_CONNECTION_INVITATION = "STORE_VC_WALLET_CONNECTION_INVITATION";
5 changes: 5 additions & 0 deletions services/minespace-web/common/constants/reducerTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,8 @@ export const GET_DAM = "GET_DAM";

// Alerts
export const GET_GLOBAL_ALERTS = "GET_GLOBAL_ALERTS";

//Verficable Credentials
export const VERIFIABLE_CREDENTIALS = "VERIFIABLE_CREDENTIALS";
export const CREATE_VC_WALLET_CONNECTION_INVITATION = "CREATE_VC_WALLET_CONNECTION_INVITATION";
export const FETCH_VC_WALLET_CONNECTION_INVITATIONS = "FETCH_VC_WALLET_CONNECTION_INVITATIONS";
Loading
Loading