From 9101d80c121aa3d4793f289009fd7cd4dd8837a3 Mon Sep 17 00:00:00 2001 From: reluc Date: Thu, 20 Jul 2023 18:38:12 +0200 Subject: [PATCH] feat(frontend/shared): add support for reading certifications of profile --- .../certificates/certificates.component.html | 5 ++-- .../certificates/certificates.component.ts | 2 +- .../profile-body/profile-body.component.ts | 3 +++ .../interfaces/certificate.interface.ts | 6 ----- .../app/modules/profiles/interfaces/index.ts | 1 - .../profiles/interfaces/profile.interface.ts | 3 ++- .../interfaces/certificate.interface.ts | 7 ++++++ .../services/certificate-contract.service.ts | 25 +++++++++++++++++++ .../services/my3sec-hub-contract.service.ts | 10 +++++++- .../app/shared/services/profile.service.ts | 21 +++++++++++++++- 10 files changed, 69 insertions(+), 14 deletions(-) delete mode 100644 frontend/src/app/modules/profiles/interfaces/certificate.interface.ts create mode 100644 frontend/src/app/shared/services/certificate-contract.service.ts diff --git a/frontend/src/app/modules/profiles/components/certificates/certificates.component.html b/frontend/src/app/modules/profiles/components/certificates/certificates.component.html index 20caf51..41f1c0f 100644 --- a/frontend/src/app/modules/profiles/components/certificates/certificates.component.html +++ b/frontend/src/app/modules/profiles/components/certificates/certificates.component.html @@ -6,16 +6,15 @@

Certificates< *ngFor="let certificate of certificates">
- {{ certificate?.icon }} + {{ certificate?.image }}
{{ certificate?.name }}
- {{ certificate?.achievement }} {{ certificate?.date | date }}
- {{ certificate?.icon }} + {{ certificate?.image }}
diff --git a/frontend/src/app/modules/profiles/components/certificates/certificates.component.ts b/frontend/src/app/modules/profiles/components/certificates/certificates.component.ts index 86a4d35..a865775 100644 --- a/frontend/src/app/modules/profiles/components/certificates/certificates.component.ts +++ b/frontend/src/app/modules/profiles/components/certificates/certificates.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { Certificate } from './../../../../modules/profiles/interfaces'; +import { Certificate } from '@shared/interfaces'; @Component({ selector: 'app-certificates', diff --git a/frontend/src/app/modules/profiles/components/profile-body/profile-body.component.ts b/frontend/src/app/modules/profiles/components/profile-body/profile-body.component.ts index 29ac67a..254747a 100644 --- a/frontend/src/app/modules/profiles/components/profile-body/profile-body.component.ts +++ b/frontend/src/app/modules/profiles/components/profile-body/profile-body.component.ts @@ -108,6 +108,9 @@ export class ProfileBodyComponent implements OnInit { distinct() ); + this.profileData$ + .pipe(switchMap(profile => this.my3secHubContractService.getCertificates(parseInt(profile.id)))) + .subscribe(a => console.log(a)); this.loadingService.waitForObservables([this.profileData$, this.organizations$, this.projects$]); } diff --git a/frontend/src/app/modules/profiles/interfaces/certificate.interface.ts b/frontend/src/app/modules/profiles/interfaces/certificate.interface.ts deleted file mode 100644 index b020e71..0000000 --- a/frontend/src/app/modules/profiles/interfaces/certificate.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Certificate { - name: string; - icon: string; - achievement: string; - date: Date; -} diff --git a/frontend/src/app/modules/profiles/interfaces/index.ts b/frontend/src/app/modules/profiles/interfaces/index.ts index d167637..1bfcbd3 100644 --- a/frontend/src/app/modules/profiles/interfaces/index.ts +++ b/frontend/src/app/modules/profiles/interfaces/index.ts @@ -1,5 +1,4 @@ export * from './skill.interface'; -export * from './certificate.interface'; export * from './profile-energy-data.interface'; export * from './endorse-dialog-data.interface'; export * from './endorse-item.interface'; diff --git a/frontend/src/app/modules/profiles/interfaces/profile.interface.ts b/frontend/src/app/modules/profiles/interfaces/profile.interface.ts index b30fb98..24a46dc 100644 --- a/frontend/src/app/modules/profiles/interfaces/profile.interface.ts +++ b/frontend/src/app/modules/profiles/interfaces/profile.interface.ts @@ -1,6 +1,7 @@ import { ProfileMetadata } from 'app/shared/interfaces'; -import { Certificate } from './certificate.interface'; +import { Certificate } from '@shared/interfaces/certificate.interface'; + import { ProfileEnergyData } from './profile-energy-data.interface'; import { Project } from './project.interface'; import { Skill } from './skill.interface'; diff --git a/frontend/src/app/shared/interfaces/certificate.interface.ts b/frontend/src/app/shared/interfaces/certificate.interface.ts index 591adb8..c33f2d9 100644 --- a/frontend/src/app/shared/interfaces/certificate.interface.ts +++ b/frontend/src/app/shared/interfaces/certificate.interface.ts @@ -3,3 +3,10 @@ export interface CertificateMetadata { description: string; image: string; } + +export interface Certificate extends CertificateMetadata { + id: number; + profileId: number; + organizationAddress: string; + date?: Date; +} diff --git a/frontend/src/app/shared/services/certificate-contract.service.ts b/frontend/src/app/shared/services/certificate-contract.service.ts new file mode 100644 index 0000000..d9d5a8f --- /dev/null +++ b/frontend/src/app/shared/services/certificate-contract.service.ts @@ -0,0 +1,25 @@ +import { environment } from 'environments/environment'; +import { ethers, providers } from 'ethers'; +import { Observable, from } from 'rxjs'; + +import { Injectable } from '@angular/core'; + +import { CertificateNFT, CertificateNFT__factory } from '@vaimee/my3sec-contracts/dist'; + +@Injectable({ + providedIn: 'root', +}) +export class CertificateContractService { + private contractAddress = environment.contracts.certificateNFT; + private contract: CertificateNFT; + + constructor() { + const provider = new ethers.providers.Web3Provider(window.ethereum as providers.ExternalProvider, 'any'); + const signer = provider.getSigner(); + this.contract = CertificateNFT__factory.connect(this.contractAddress, signer); + } + + public getCertificateMetadataURI(certificateId: number): Observable { + return from(this.contract.tokenURI(certificateId)); + } +} diff --git a/frontend/src/app/shared/services/my3sec-hub-contract.service.ts b/frontend/src/app/shared/services/my3sec-hub-contract.service.ts index 1f68372..9a26ca1 100644 --- a/frontend/src/app/shared/services/my3sec-hub-contract.service.ts +++ b/frontend/src/app/shared/services/my3sec-hub-contract.service.ts @@ -7,8 +7,9 @@ import { Injectable } from '@angular/core'; import { MetamaskService } from '@auth/services/metamask.service'; -import { Events__factory, My3SecHub, My3SecHub__factory } from '@vaimee/my3sec-contracts/dist'; +import { Events, Events__factory, My3SecHub, My3SecHub__factory } from '@vaimee/my3sec-contracts/dist'; import { DataTypes } from '@vaimee/my3sec-contracts/dist/contracts/My3SecHub'; +import { CertificateIssuedEvent } from '@vaimee/my3sec-contracts/dist/contracts/common/libraries/Events'; @Injectable({ providedIn: 'root', @@ -17,11 +18,13 @@ export class My3secHubContractService { private contractAddress = environment.contracts.my3secHub; private contract: My3SecHub; + private events: Events; constructor(private metamaskService: MetamaskService) { const provider = new ethers.providers.Web3Provider(window.ethereum as providers.ExternalProvider, 'any'); const signer = provider.getSigner(); this.contract = My3SecHub__factory.connect(this.contractAddress, signer); + this.events = Events__factory.connect(this.contractAddress, signer); } public getDefaultProfile(account: string): Observable { @@ -46,6 +49,11 @@ export class My3secHubContractService { ); } + public getCertificates(profileId: number): Observable { + const filter = this.events.filters.CertificateIssued(null, profileId); + return from(this.events.queryFilter(filter)); + } + public createProfile(metadataURI: string): Observable { return from(this.contract.createProfile({ metadataURI })).pipe( switchMap(this.wait), diff --git a/frontend/src/app/shared/services/profile.service.ts b/frontend/src/app/shared/services/profile.service.ts index a72d8d3..56ecd45 100644 --- a/frontend/src/app/shared/services/profile.service.ts +++ b/frontend/src/app/shared/services/profile.service.ts @@ -16,10 +16,11 @@ import { Injectable } from '@angular/core'; import { MetamaskService } from '@auth/services/metamask.service'; -import { Profile, ProfileMetadata } from '@shared/interfaces'; +import { Certificate, CertificateMetadata, Profile, ProfileMetadata } from '@shared/interfaces'; import { EndorserItem } from '@profiles/interfaces'; +import { CertificateContractService } from './certificate-contract.service'; import { EnergyWalletContractService } from './energy-wallet-contract.service'; import { IpfsService } from './ipfs.service'; import { My3secHubContractService } from './my3sec-hub-contract.service'; @@ -31,6 +32,7 @@ export class ProfileService { constructor( private my3secHub: My3secHubContractService, private energyWalletContract: EnergyWalletContractService, + private certificateContract: CertificateContractService, private ipfsService: IpfsService, private metamaskService: MetamaskService ) {} @@ -163,6 +165,23 @@ export class ProfileService { ); } + public getCertificates(profileId: number): Observable { + return this.my3secHub.getCertificates(profileId).pipe( + concatMap(certificates => certificates), + switchMap(event => { + return this.certificateContract.getCertificateMetadataURI(event.args.certificateId.toNumber()).pipe( + switchMap(data => this.ipfsService.retrieveJSON(data)), + map(metadata => ({ + ...metadata, + id: event.args.certificateId.toNumber(), + organizationAddress: event.args.from, + profileId: event.args.profileId.toNumber(), + })) + ); + }) + ); + } + public getUserId(): Observable { return this.my3secHub.getDefaultProfile(this.metamaskService.userAddress).pipe(map(({ id }) => id.toNumber())); }