diff --git a/server/src/controllers/contracts.ts b/server/src/controllers/contracts.ts index c4a7ca6..2a6f900 100644 --- a/server/src/controllers/contracts.ts +++ b/server/src/controllers/contracts.ts @@ -69,6 +69,26 @@ export class ContractsController { return { type: 'message', id: api.message }; } + @Post('/apifabric') + @HttpCode(202) + @ResponseSchema(AsyncResponse) + @OpenAPI({ summary: 'Define a new contract API with Fabric' }) + async createAPIFabric(@Body() body: ContractAPI): Promise { + // See ContractsTemplateController and keep template code up to date. + const api = await firefly.createContractAPI({ + name: body.name, + interface: { + name: body.interfaceName, + version: body.interfaceVersion, + }, + location: { + chaincode: body.chaincode, + channel: body.channel, + }, + }); + return { type: 'message', id: api.message }; + } + @Get('/interface') @ResponseSchema(ContractInterfaceLookup, { isArray: true }) @OpenAPI({ summary: 'List contract interfaces' }) diff --git a/server/src/interfaces.ts b/server/src/interfaces.ts index 7acf1c5..c6893f3 100644 --- a/server/src/interfaces.ts +++ b/server/src/interfaces.ts @@ -250,7 +250,16 @@ export class ContractAPI { interfaceVersion: string; @IsString() - address: string; + @IsOptional() + address?: string; + + @IsString() + @IsOptional() + channel?: string; + + @IsString() + @IsOptional() + chaincode?: string; } export class ContractAPIURLs { diff --git a/server/test/contracts.test.ts b/server/test/contracts.test.ts index 5a3212e..7e22973 100644 --- a/server/test/contracts.test.ts +++ b/server/test/contracts.test.ts @@ -101,6 +101,34 @@ describe('Smart Contracts', () => { }); }); + test('Create contract API with Fabric', async () => { + const req: ContractAPI = { + name: 'my-api-fabric', + channel: '0x123', + chaincode: 'chaincode', + interfaceName: 'my-contract', + interfaceVersion: '1.0', + }; + const api = { + name: 'my-api-fabric', + message: 'msg1', + } as FireFlyContractAPIResponse; + + mockFireFly.createContractAPI.mockResolvedValueOnce(api); + + await request(server) + .post('/api/contracts/apifabric') + .send(req) + .expect(202) + .expect({ type: 'message', id: 'msg1' }); + + expect(mockFireFly.createContractAPI).toHaveBeenCalledWith({ + interface: { name: 'my-contract', version: '1.0' }, + location: { chaincode: 'chaincode', channel: '0x123' }, + name: 'my-api-fabric', + }); + }); + test('Get contract Interfaces', async () => { const int = [ { diff --git a/ui/src/components/Buttons/RunButton.tsx b/ui/src/components/Buttons/RunButton.tsx index 6d0f14e..5e6b80c 100644 --- a/ui/src/components/Buttons/RunButton.tsx +++ b/ui/src/components/Buttons/RunButton.tsx @@ -2,6 +2,7 @@ import { ArrowForwardIos } from '@mui/icons-material'; import { Button, CircularProgress, Grid, Typography } from '@mui/material'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; +import { SDK_PATHS } from '../../constants/SDK_PATHS'; import { TUTORIAL_CATEGORIES, TUTORIAL_FORMS, @@ -10,6 +11,7 @@ import { ApplicationContext } from '../../contexts/ApplicationContext'; import { EventContext } from '../../contexts/EventContext'; import { FormContext } from '../../contexts/FormContext'; import { SnackbarContext } from '../../contexts/SnackbarContext'; +import { BLOCKCHAIN_TYPE } from '../../enums/enums'; import { DEFAULT_BORDER_RADIUS } from '../../theme'; import { isSuccessfulResponse } from '../../utils/strings'; @@ -22,8 +24,12 @@ interface Props { export const RunButton: React.FC = ({ endpoint, payload, disabled }) => { const { t } = useTranslation(); // const [showSnackbar, setShowSnackbar] = useState(false); - const { setApiStatus, setApiResponse, payloadMissingFields } = - useContext(ApplicationContext); + const { + blockchainPlugin, + setApiStatus, + setApiResponse, + payloadMissingFields, + } = useContext(ApplicationContext); const { addAwaitedEventID, awaitedEventID } = useContext(EventContext); const { categoryID, isBlob, poolObject } = useContext(FormContext); const { setMessage, setMessageType } = useContext(SnackbarContext); @@ -34,7 +40,13 @@ export const RunButton: React.FC = ({ endpoint, payload, disabled }) => { setApiStatus(undefined); setApiResponse({}); managePayload(); - const postEndpoint = isBlob ? endpoint + 'blob' : endpoint; + let postEndpoint = isBlob ? endpoint + 'blob' : endpoint; + if ( + blockchainPlugin === BLOCKCHAIN_TYPE.FABRIC && + endpoint === SDK_PATHS.contractsApi + ) { + postEndpoint = endpoint + BLOCKCHAIN_TYPE.FABRIC; + } const reqDetails: any = { method: 'POST', body: isBlob diff --git a/ui/src/components/Forms/Contracts/RegisterContractApiForm.tsx b/ui/src/components/Forms/Contracts/RegisterContractApiForm.tsx index 4d1f89d..952fb83 100644 --- a/ui/src/components/Forms/Contracts/RegisterContractApiForm.tsx +++ b/ui/src/components/Forms/Contracts/RegisterContractApiForm.tsx @@ -70,7 +70,7 @@ export const RegisterContractApiForm: React.FC = () => { contractInterfaces[contractInterfaceIdx]?.version || '', chaincode: chaincode, channel: channel, - address: undefined, + address: '', }); } }, [