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

Feat v230223 v230310 special provider for photos taken from capture app #2667

Merged
8 changes: 4 additions & 4 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { CameraService } from './shared/camera/camera.service';
import { CaptureService } from './shared/capture/capture.service';
import { CollectorService } from './shared/collector/collector.service';
import { CapacitorFactsProvider } from './shared/collector/facts/capacitor-facts-provider/capacitor-facts-provider.service';
import { WebCryptoApiSignatureProvider } from './shared/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { CaptureAppWebCryptoApiSignatureProvider } from './shared/collector/signature/capture-app-web-crypto-api-signature-provider/capture-app-web-crypto-api-signature-provider.service';
import { DiaBackendAssetUploadingService } from './shared/dia-backend/asset/uploading/dia-backend-asset-uploading.service';
import { DiaBackendAuthService } from './shared/dia-backend/auth/dia-backend-auth.service';
import { DiaBackendNotificationService } from './shared/dia-backend/notification/dia-backend-notification.service';
Expand All @@ -33,7 +33,7 @@ export class AppComponent {
private readonly iconRegistry: MatIconRegistry,
private readonly sanitizer: DomSanitizer,
private readonly capacitorFactsProvider: CapacitorFactsProvider,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly capAppWebCryptoApiSignatureProvider: CaptureAppWebCryptoApiSignatureProvider,
private readonly captureService: CaptureService,
private readonly cameraService: CameraService,
private readonly errorService: ErrorService,
Expand Down Expand Up @@ -92,10 +92,10 @@ export class AppComponent {
}

initializeCollector() {
this.webCryptoApiSignatureProvider.initialize();
this.capAppWebCryptoApiSignatureProvider.initialize();
this.collectorService.addFactsProvider(this.capacitorFactsProvider);
this.collectorService.addSignatureProvider(
this.webCryptoApiSignatureProvider
this.capAppWebCryptoApiSignatureProvider
);
}

Expand Down
18 changes: 13 additions & 5 deletions src/app/features/home/custom-camera/custom-camera.page.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sultanmyrza can you please share with me if photo upload is involved in this PR? According to the source code, I think it is mainly for the photos taken from capture app. However, it mentioned "uploadToCapture" so that I want to confirm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tammyyang, In this PR I changed uploadToCapture parameters.
Now I pass extra parameter curCaptureCameraSource that can be PHOTO (when picked from gallery) or CAMERA (when taken photo from camera)

Then I use that parameter when making decision.

If curCaptureCameraSource = PHOTO => UploaderWebCryptoApiSignatureProvider
if curCaptureCameraSource = CAMERA => CaptureAppWebCryptoApiSignatureProvider

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Photo upload is involved in way that we pass extra param (PHOTO or CAMERA)

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import { CameraSource } from '@capacitor/camera';
import { Capacitor, PluginListenerHandle } from '@capacitor/core';
import { Platform } from '@ionic/angular';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
Expand All @@ -13,7 +14,7 @@ import {
CustomOrientation,
PreviewCamera,
} from '@numbersprotocol/preview-camera';
import { BehaviorSubject, combineLatest, interval, Subscription } from 'rxjs';
import { BehaviorSubject, Subscription, combineLatest, interval } from 'rxjs';
import {
finalize,
map,
Expand Down Expand Up @@ -49,6 +50,7 @@ export class CustomCameraPage implements OnInit, OnDestroy {
maxRecordTimeInSeconds = MAX_RECORD_TIME_IN_MILLISECONDS / 1000;
maxRecordTimeInMilliseconds = MAX_RECORD_TIME_IN_MILLISECONDS;
curRecordTimeInPercent$ = new BehaviorSubject<number>(0);
curCaptureCameraSource: CameraSource = CameraSource.Camera;
isRecording$ = new BehaviorSubject(false);

mode$ = new BehaviorSubject<CameraMode>('photo');
Expand Down Expand Up @@ -161,14 +163,18 @@ export class CustomCameraPage implements OnInit, OnDestroy {

// PreviewCamera Plugin methods
private async onCapturePhotoFinished(data: CaptureResult): Promise<void> {
this.uploadItem(data, 'image');
this.prePublish(data, 'image', CameraSource.Camera);
}

private async onCaptureVideoFinished(data: CaptureResult): Promise<void> {
this.uploadItem(data, 'video');
this.prePublish(data, 'video', CameraSource.Camera);
}

private async uploadItem(data: CaptureResult, type: 'image' | 'video') {
private async prePublish(
data: CaptureResult,
type: 'image' | 'video',
source: CameraSource
) {
if (data.errorMessage) {
await this.errorService.toastError$(data.errorMessage).toPromise();
} else if (data.filePath) {
Expand All @@ -181,6 +187,7 @@ export class CustomCameraPage implements OnInit, OnDestroy {
this.curCaptureMimeType = mimeType;
this.curCaptureType = type;
this.curCaptureSrc = Capacitor.convertFileSrc(filePath);
this.curCaptureCameraSource = source;
this.lastCaptureMode = this.mode$.value;
this.mode$.next('pre-publish');

Expand Down Expand Up @@ -276,7 +283,8 @@ export class CustomCameraPage implements OnInit, OnDestroy {
if (this.curCaptureFilePath && this.curCaptureType) {
this.customCameraService.uploadToCapture(
this.curCaptureFilePath,
this.curCaptureType
this.curCaptureType,
this.curCaptureCameraSource
);
this.leaveCustomCamera();
}
Expand Down
9 changes: 7 additions & 2 deletions src/app/features/home/custom-camera/custom-camera.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { CameraSource } from '@capacitor/camera';
import { Capacitor } from '@capacitor/core';
import { FilesystemPlugin } from '@capacitor/filesystem';
import { Platform } from '@ionic/angular';
Expand Down Expand Up @@ -48,7 +49,11 @@ export class CustomCameraService {
return newItem;
}

async uploadToCapture(filePath: string, type: CustomCameraMediaType) {
async uploadToCapture(
filePath: string,
type: CustomCameraMediaType,
source: CameraSource
) {
const itemToUpload = this.mediaItemFromFilePath(filePath, type);

try {
Expand All @@ -57,7 +62,7 @@ export class CustomCameraService {
.toPromise();
const base64 = await blobToBase64(itemBlob);
const mimeType = itemToUpload.mimeType;
await this.captureService.capture({ base64, mimeType });
await this.captureService.capture({ base64, mimeType, source });
await this.removeFile(filePath);
} catch (error) {
const errMsg = this.translocoService.translate(`error.internetError`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Inject, Injectable } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import '@capacitor-community/http';
import { Http } from '@capacitor-community/http';
import { CameraSource } from '@capacitor/camera';
import { Capacitor } from '@capacitor/core';
import {
Directory as FilesystemDirectory,
Expand Down Expand Up @@ -84,7 +85,11 @@ export class GoProMediaService {
const mimeType = urlIsImage(mediaFile.url) ? 'image/jpeg' : 'video/mp4';
isDownloaded = true;

await this.captureService.capture({ base64, mimeType });
await this.captureService.capture({
base64,
mimeType,
source: CameraSource.Camera,
});
isCaptured = true;

// delete temp downloaded file
Expand Down
9 changes: 5 additions & 4 deletions src/app/features/settings/settings.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Clipboard } from '@capacitor/clipboard';
import { IonModal } from '@ionic/angular';
import { TranslocoService } from '@ngneat/transloco';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { defer, EMPTY, Subject } from 'rxjs';
import { EMPTY, Subject, defer } from 'rxjs';
import {
catchError,
concatMapTo,
Expand All @@ -18,7 +18,7 @@ import {
} from 'rxjs/operators';
import { BlockingActionService } from '../../shared/blocking-action/blocking-action.service';
import { CapacitorFactsProvider } from '../../shared/collector/facts/capacitor-facts-provider/capacitor-facts-provider.service';
import { WebCryptoApiSignatureProvider } from '../../shared/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { CaptureAppWebCryptoApiSignatureProvider } from '../../shared/collector/signature/capture-app-web-crypto-api-signature-provider/capture-app-web-crypto-api-signature-provider.service';
import { ConfirmAlert } from '../../shared/confirm-alert/confirm-alert.service';
import { Database } from '../../shared/database/database.service';
import { DiaBackendAuthService } from '../../shared/dia-backend/auth/dia-backend-auth.service';
Expand Down Expand Up @@ -62,7 +62,8 @@ export class SettingsPage {
private readonly requiredClicks = 7;
showHiddenOption = false;

private readonly privateKey$ = this.webCryptoApiSignatureProvider.privateKey$;
private readonly privateKey$ =
this.capAppWebCryptoApiSignatureProvider.privateKey$;
readonly privateKeyTruncated$ = this.privateKey$.pipe(
map(key => {
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
Expand All @@ -86,7 +87,7 @@ export class SettingsPage {
private readonly versionService: VersionService,
private readonly router: Router,
private readonly route: ActivatedRoute,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly capAppWebCryptoApiSignatureProvider: CaptureAppWebCryptoApiSignatureProvider,
private readonly snackBar: MatSnackBar
) {}

Expand Down
8 changes: 4 additions & 4 deletions src/app/features/wallets/wallets.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { NgxQrcodeElementTypes } from '@techiediaries/ngx-qrcode';
import { BehaviorSubject, fromEvent } from 'rxjs';
import { concatMap, first, map, tap } from 'rxjs/operators';
import { WebCryptoApiSignatureProvider } from '../../shared/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { CaptureAppWebCryptoApiSignatureProvider } from '../../shared/collector/signature/capture-app-web-crypto-api-signature-provider/capture-app-web-crypto-api-signature-provider.service';
import { DiaBackendAuthService } from '../../shared/dia-backend/auth/dia-backend-auth.service';
import { BUBBLE_IFRAME_URL } from '../../shared/dia-backend/secret';
import { DiaBackendWalletService } from '../../shared/dia-backend/wallet/dia-backend-wallet.service';
Expand All @@ -20,8 +20,8 @@ import { BubbleToIonicPostMessage } from '../../shared/iframe/iframe';
styleUrls: ['./wallets.page.scss'],
})
export class WalletsPage {
readonly publicKey$ = this.webCryptoApiSignatureProvider.publicKey$;
readonly privateKey$ = this.webCryptoApiSignatureProvider.privateKey$;
readonly publicKey$ = this.capAppWebCryptoApiSignatureProvider.publicKey$;
readonly privateKey$ = this.capAppWebCryptoApiSignatureProvider.privateKey$;
readonly assetWalletAddr$ = this.diaBackendWalletService.assetWalletAddr$;

readonly networkConnected$ = this.diaBackendWalletService.networkConnected$;
Expand All @@ -43,7 +43,7 @@ export class WalletsPage {
private readonly diaBackendAuthService: DiaBackendAuthService,
private readonly snackBar: MatSnackBar,
private readonly translocoService: TranslocoService,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly capAppWebCryptoApiSignatureProvider: CaptureAppWebCryptoApiSignatureProvider,
private readonly router: Router,
private readonly navController: NavController
) {}
Expand Down
10 changes: 5 additions & 5 deletions src/app/shared/actions/service/order-history.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { BehaviorSubject, combineLatest, defer, EMPTY, Observable } from 'rxjs';
import { BehaviorSubject, EMPTY, Observable, combineLatest, defer } from 'rxjs';
import { concatMap, first, map, pluck, tap } from 'rxjs/operators';
import { WebCryptoApiSignatureProvider } from '../../collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { CaptureAppWebCryptoApiSignatureProvider } from '../../collector/signature/capture-app-web-crypto-api-signature-provider/capture-app-web-crypto-api-signature-provider.service';
import { DiaBackendAssetRepository } from '../../dia-backend/asset/dia-backend-asset-repository.service';
import { BUBBLE_DB_URL } from '../../dia-backend/secret';
import { NetworkAppOrder } from '../../dia-backend/store/dia-backend-store.service';
Expand All @@ -25,7 +25,7 @@ export class OrderHistoryService {

constructor(
private readonly httpClient: HttpClient,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly capAppWebCryptoApiSignatureProvider: CaptureAppWebCryptoApiSignatureProvider,
private readonly proofRepository: ProofRepository,
private readonly sanitizer: DomSanitizer,
private readonly diaBackendTransactionRepository: DiaBackendTransactionRepository,
Expand All @@ -50,7 +50,7 @@ export class OrderHistoryService {

createOrderHistory$(networkAppOrder: NetworkAppOrder, cid: string) {
return defer(() =>
this.webCryptoApiSignatureProvider.publicKey$.pipe(
this.capAppWebCryptoApiSignatureProvider.publicKey$.pipe(
concatMap(publicKey =>
this.httpClient.post<BubbleCreateNewThingResponse>(
`${BUBBLE_DB_URL}/api/1.1/obj/order`,
Expand All @@ -77,7 +77,7 @@ export class OrderHistoryService {
*/
getOrdersHistory$() {
return defer(() =>
this.webCryptoApiSignatureProvider.publicKey$.pipe(
this.capAppWebCryptoApiSignatureProvider.publicKey$.pipe(
concatMap(publicKey =>
this.httpClient
.get<GetActionsResponse<BubbleOrderHistoryRecord>>(
Expand Down
2 changes: 2 additions & 0 deletions src/app/shared/camera/camera.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class CameraService {
resolve({
base64,
mimeType: file.type as MimeType,
source: CameraSource.Camera,
})
);
};
Expand All @@ -99,6 +100,7 @@ function cameraPhotoToPhoto(cameraPhoto: CameraPhoto): Media {
mimeType: fromExtension(cameraPhoto.format),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
base64: cameraPhoto.base64String!,
source: CameraSource.Camera,
};
}

Expand Down
9 changes: 6 additions & 3 deletions src/app/shared/capture/capture.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { CameraSource } from '@capacitor/camera';
import { BehaviorSubject } from 'rxjs';
import { MimeType } from '../../utils/mime-type';
import { CollectorService } from '../collector/collector.service';
Expand All @@ -22,10 +23,10 @@ export class CaptureService {
private readonly collectorService: CollectorService
) {}

async capture(source: Media) {
async capture(media: Media) {
const proof = await Proof.from(
this.mediaStore,
{ [source.base64]: { mimeType: source.mimeType } },
{ [media.base64]: { mimeType: media.mimeType } },
{ timestamp: Date.now(), providers: {} },
{}
);
Expand All @@ -37,7 +38,8 @@ export class CaptureService {
);
const collected = await this.collectorService.run(
await proof.getAssets(),
proof.timestamp
proof.timestamp,
media.source
);
// eslint-disable-next-line rxjs/no-subject-value
const newCollectingOldProofHashes = this._collectingOldProofHashes$.value;
Expand All @@ -54,4 +56,5 @@ export class CaptureService {
export interface Media {
readonly mimeType: MimeType;
readonly base64: string;
readonly source: CameraSource;
}
14 changes: 9 additions & 5 deletions src/app/shared/collector/collector.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable class-methods-use-this */
import { TestBed } from '@angular/core/testing';
import { CameraSource } from '@capacitor/camera';
import { MimeType } from '../../utils/mime-type';
import {
AssetMeta,
Expand Down Expand Up @@ -27,15 +28,15 @@ describe('CollectorService', () => {
it('should be created', () => expect(service).toBeTruthy());

it('should get the stored proof after run', async () => {
const proof = await service.run(ASSETS, Date.now());
const proof = await service.run(ASSETS, Date.now(), CameraSource.Camera);
expect(await proof.getAssets()).toEqual(ASSETS);
});

it('should remove added truth providers', async () => {
service.addFactsProvider(mockFactsProvider);
service.removeFactsProvider(mockFactsProvider);

const proof = await service.run(ASSETS, Date.now());
const proof = await service.run(ASSETS, Date.now(), CameraSource.Camera);

expect(proof.truth.providers).toEqual({});
});
Expand All @@ -44,20 +45,20 @@ describe('CollectorService', () => {
service.addSignatureProvider(mockSignatureProvider);
service.removeSignatureProvider(mockSignatureProvider);

const proof = await service.run(ASSETS, Date.now());
const proof = await service.run(ASSETS, Date.now(), CameraSource.Camera);

expect(proof.signatures).toEqual({});
});

it('should get the stored proof with provided facts', async () => {
service.addFactsProvider(mockFactsProvider);
const proof = await service.run(ASSETS, Date.now());
const proof = await service.run(ASSETS, Date.now(), CameraSource.Camera);
expect(proof.truth.providers).toEqual({ [mockFactsProvider.id]: FACTS });
});

it('should get the stored proof with provided signature', async () => {
service.addSignatureProvider(mockSignatureProvider);
const proof = await service.run(ASSETS, Date.now());
const proof = await service.run(ASSETS, Date.now(), CameraSource.Camera);
expect(proof.signatures).toEqual({ [mockSignatureProvider.id]: SIGNATURE });
});
});
Expand Down Expand Up @@ -104,6 +105,9 @@ const SIGNATURE: Signature = {
};
class MockSignatureProvider implements SignatureProvider {
readonly id = 'MockSignatureProvider';
idFor(_source: any): string {
return this.id;
}
// eslint-disable-next-line @typescript-eslint/require-await
async provide(_: string) {
return SIGNATURE;
Expand Down
Loading