import { ActiveUserGuard , BlockchainAccountGuard , BlockchainAccountDecorator , ExceptionInterceptor , Roles , RolesGuard } from '@energyweb/origin-backend-utils' ; import { Body , Controller , Get , Post , UseGuards , Param , ParseIntPipe , Put , UseInterceptors , HttpStatus , Query , UsePipes , ValidationPipe , NotFoundException , HttpCode } from '@nestjs/common' ; import { AuthGuard } from '@nestjs/passport' ; import { CommandBus , QueryBus } from '@nestjs/cqrs' ; import { Role } from '@energyweb/origin-backend-core' ; import { ApiBearerAuth , ApiBody , ApiOkResponse , ApiTags , ApiQuery } from '@nestjs/swagger' ; import moment from 'moment' ; import { BigNumber } from 'ethers' ; import { CertificateEvent } from '../../types' ; import { certificateToDto } from './utils' ; import { Certificate } from './certificate.entity' ; import { GetAggregateCertifiedEnergyByDeviceIdQuery , GetAllCertificateEventsQuery , GetAllCertificatesQuery , GetCertificateByTxHashQuery , GetCertificateQuery } from './queries' ; import { ClaimCertificateCommand , IssueCertificateCommand , TransferCertificateCommand } from './commands' ; import { CertificateDTO , ClaimCertificateDTO , IssueCertificateDTO , TransferCertificateDTO } from './dto' ; import { TxHashDTO } from './dto/tx-hash.dto' ; @ ApiTags ( 'certificates' ) @ ApiBearerAuth ( 'access-token' ) @ Controller ( 'certificate' ) @ UseInterceptors ( ExceptionInterceptor ) @ UsePipes ( ValidationPipe ) export class CertificateController { constructor ( public readonly commandBus , public readonly queryBus ) { } @ Get ( '/:id' ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard ) @ ApiOkResponse ( { type : CertificateDTO , description : 'Returns a Certificate' } ) public async get ( @ Param ( 'id' , new ParseIntPipe ( ) ) id , @ BlockchainAccountDecorator ( ) blockchainAddress ) { const certificate = await this . queryBus . execute < GetCertificateQuery , Certificate > ( new GetCertificateQuery ( id ) ) ; if ( ! certificate ) { throw new NotFoundException ( `Certificate with ID ${ id } does not exist.` ) ; } return certificateToDto ( certificate , blockchainAddress ) ; } @ Get ( '/by-transaction/:txHash' ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard ) @ ApiOkResponse ( { type : [ CertificateDTO ] , description : 'Returns Certificates that were created in the transaction' } ) public async getByTxHash ( @ Param ( 'txHash' ) txHash , @ BlockchainAccountDecorator ( ) blockchainAddress ) { const certificates = await this . queryBus . execute < GetCertificateByTxHashQuery , Certificate [ ] > ( new GetCertificateByTxHashQuery ( txHash ) ) ; if ( certificates ?. length === 0 ) { throw new NotFoundException ( `No certificates were issued in the tx with hash ${ txHash }.` ) ; } return certificates . map ( ( cert ) => certificateToDto ( cert , blockchainAddress ) ) ; } @ Get ( ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard ) @ ApiOkResponse ( { type : [ CertificateDTO ] , description : 'Returns all Certificates' } ) @ ApiQuery ( { name : 'generationEndFrom' , description : 'Date-alike filter for `generationEnd` field (lower boundary)' , required : false } ) @ ApiQuery ( { name : 'generationEndTo' , description : 'Date-alike filter for `generationEnd` field (upper boundary)' , required : false } ) @ ApiQuery ( { name : 'generationStartFrom' , description : 'Date-alike filter for `generationStart` field (upper boundary)' , required : false } ) @ ApiQuery ( { name : 'generationStartTo' , description : 'Date-alike filter for `generationStart` field (upper boundary)' , required : false } ) @ ApiQuery ( { name : 'creationTimeFrom' , description : 'Date-alike filter for `creationTime` field (upper boundary)' , required : false } ) @ ApiQuery ( { name : 'creationTimeTo' , description : 'Date-alike filter for `creationTime` field (upper boundary)' , required : false } ) @ ApiQuery ( { name : 'deviceId' , description : 'Filter for deviceId field' , required : false } ) public async getAll ( @ BlockchainAccountDecorator ( ) blockchainAddress , @ Query ( 'generationEndFrom' ) generationEndFrom ? , @ Query ( 'generationEndTo' ) generationEndTo ? , @ Query ( 'generationStartFrom' ) generationStartFrom ? , @ Query ( 'generationStartTo' ) generationStartTo ? , @ Query ( 'creationTimeFrom' ) creationTimeFrom ? , @ Query ( 'creationTimeTo' ) creationTimeTo ? , @ Query ( 'deviceId' ) deviceId ? ) { const certificates = await this . queryBus . execute < GetAllCertificatesQuery , Certificate [ ] > ( new GetAllCertificatesQuery ( { generationEndFrom : generationEndFrom ? new Date ( generationEndFrom ) : undefined , generationEndTo : generationEndTo ? new Date ( generationEndTo ) : undefined , generationStartFrom : generationStartFrom ? new Date ( generationStartFrom ) : undefined , generationStartTo : generationStartTo ? new Date ( generationStartTo ) : undefined , creationTimeFrom : creationTimeFrom ? new Date ( creationTimeFrom ) : undefined , creationTimeTo : creationTimeTo ? new Date ( creationTimeTo ) : undefined , deviceId } ) ) ; return certificates . map ( ( certificate ) => certificateToDto ( certificate , blockchainAddress ) ) ; } @ Get ( '/issuer/certified/:deviceId' ) @ ApiOkResponse ( { type : String , description : 'Returns SUM of certified energy by device ID' } ) public async getAggregateCertifiedEnergyByDeviceId ( @ Param ( 'deviceId' ) deviceId , @ Query ( 'start' ) start , @ Query ( 'end' ) end ) { const startDateToUnix = moment ( start ) . unix ( ) ; const endDateToUnix = moment ( end ) . unix ( ) ; const result = await this . queryBus . execute < GetAggregateCertifiedEnergyByDeviceIdQuery , BigNumber > ( new GetAggregateCertifiedEnergyByDeviceIdQuery ( deviceId , startDateToUnix , endDateToUnix ) ) ; return result . toString ( ) ; } @ Post ( ) @ HttpCode ( HttpStatus . OK ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard , RolesGuard , BlockchainAccountGuard ) @ Roles ( Role . Issuer ) @ ApiOkResponse ( { type : TxHashDTO , description : 'Triggers an issuance transaction and returns the transaction hash' } ) @ ApiBody ( { type : IssueCertificateDTO } ) public async issue ( @ BlockchainAccountDecorator ( ) blockchainAddress , @ Body ( ) dto ) { const tx = await this . commandBus . execute ( new IssueCertificateCommand ( dto . to , dto . energy , dto . fromTime , dto . toTime , dto . deviceId , blockchainAddress , dto . isPrivate , dto . metadata ) ) ; return { txHash : tx . hash } ; } @ Put ( '/:id/transfer' ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard , BlockchainAccountGuard ) @ ApiBody ( { type : TransferCertificateDTO } ) @ ApiOkResponse ( { type : TxHashDTO , description : 'Triggers a Transfer transaction and returns the transaction hash' } ) public async transfer ( @ BlockchainAccountDecorator ( ) blockchainAddress , @ Param ( 'id' , new ParseIntPipe ( ) ) certificateId , @ Body ( ) dto ) { const tx = await this . commandBus . execute ( new TransferCertificateCommand ( certificateId , blockchainAddress , dto . to , dto . amount , dto . delegated ) ) ; return { txHash : tx . hash } ; } @ Put ( '/:id/claim' ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard , BlockchainAccountGuard ) @ ApiBody ( { type : ClaimCertificateDTO } ) @ ApiOkResponse ( { type : TxHashDTO , description : 'Triggers a Transfer transaction and returns the transaction hash' } ) public async claim ( @ BlockchainAccountDecorator ( ) blockchainAddress , @ Param ( 'id' , new ParseIntPipe ( ) ) certificateId , @ Body ( ) dto ) { const tx = await this . commandBus . execute ( new ClaimCertificateCommand ( certificateId , dto . claimData , blockchainAddress , dto . amount ) ) ; return { txHash : tx . hash } ; } @ Get ( '/:id/events' ) @ UseGuards ( AuthGuard ( ) , ActiveUserGuard ) @ ApiOkResponse ( { type : [ CertificateEvent ] , description : 'Returns all the events for a Certificate' } ) public async getAllEvents ( @ Param ( 'id' , new ParseIntPipe ( ) ) id ) { return this . queryBus . execute ( new GetAllCertificateEventsQuery ( id ) ) ; } }