import {Injectable} from '@angular/core'; import {BehaviorSubject, Observable} from 'rxjs'; import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; import {environment} from '@src/environments/environment'; import {first} from 'rxjs/operators'; import {AccountIndex, MutableKeyStore, MutablePgpKeyStore, PGPSigner, Registry, Signer} from '@app/_helpers'; import {ArgPair, Envelope, Syncable, User} from 'cic-client-meta'; const vCard = require('vcard-parser'); @Injectable({ providedIn: 'root' }) export class UserService { headers: HttpHeaders = new HttpHeaders({'x-cic-automerge': 'client'}); keystore: MutableKeyStore = new MutablePgpKeyStore(); signer: Signer = new PGPSigner(this.keystore); registry = new Registry(environment.registryAddress); accountsMeta = []; accounts: any = []; private accountsList = new BehaviorSubject(this.accounts); accountsSubject = this.accountsList.asObservable(); actions: any = ''; private actionsList = new BehaviorSubject(this.actions); actionsSubject = this.actionsList.asObservable(); staff: any = ''; private staffList = new BehaviorSubject(this.staff); staffSubject = this.staffList.asObservable(); constructor(private http: HttpClient) { } resetPin(phone: string): Observable { const params = new HttpParams().set('phoneNumber', phone); return this.http.get(`${environment.cicUssdUrl}/pin`, { params }); } async changeAccountInfo(address: string, status: string, name: string, phoneNumber: string, age: string, type: string, token: string, failedPinAttempts: string, bio: string, gender: string, businessCategory: string, userLocation: string, location: string, locationType: string, referrer: string): Promise { const accountDetails = { status, name, phoneNumber, age, type, token, failedPinAttempts, bio, gender, businessCategory, userLocation, location, locationType, referrer }; const accountKey = await User.toKey(address); this.http.get(`${environment.cicMetaUrl}/${accountKey}`, { headers: this.headers }).pipe(first()).subscribe(async res => { const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap(); let update = []; for (const prop in accountDetails) { update.push(new ArgPair(prop, accountDetails[prop])); } syncableAccount.update(update, 'client-branch'); await this.updateMeta(syncableAccount, accountKey, this.headers); }, async error => { console.error('There is an error!', error); const syncableAccount: Syncable = new Syncable(accountKey, accountDetails); await this.updateMeta(syncableAccount, accountKey, this.headers); }); return accountKey; } async updateMeta(syncableAccount: Syncable, accountKey: string, headers: HttpHeaders): Promise { const envelope = await this.wrap(syncableAccount , this.signer); const reqBody = envelope.toJSON(); this.http.put(`${environment.cicMetaUrl}/${accountKey}`, reqBody , { headers }).pipe(first()).subscribe(res => { console.log(res); }); } getAccounts(): void { this.http.get(`${environment.cicCacheUrl}/accounts`).pipe(first()).subscribe(accounts => this.accountsList.next(accounts)); } getAccountById(id: number): Observable { return this.http.get(`${environment.cicCacheUrl}/accounts/${id}`); } getActions(): void { this.http.get(`${environment.cicCacheUrl}/actions`).pipe(first()).subscribe(actions => this.actionsList.next(actions)); } getActionById(id: string): any { return this.http.get(`${environment.cicCacheUrl}/actions/${id}`); } approveAction(id: string): Observable { return this.http.post(`${environment.cicCacheUrl}/actions/${id}`, { approval: true }); } revokeAction(id: string): Observable { return this.http.post(`${environment.cicCacheUrl}/actions/${id}`, { approval: false }); } getHistoryByUser(id: string): Observable { return this.http.get(`${environment.cicCacheUrl}/history/${id}`); } getStaff(): void { this.http.get(`${environment.cicCacheUrl}/staff`).pipe(first()).subscribe(staff => this.staffList.next(staff)); } getStaffById(id: string): Observable { return this.http.get(`${environment.cicCacheUrl}/staff/${id}`); } activateStaff(id: string): Observable { return this.http.post(`${environment.cicCacheUrl}/staff/${id}`, {status: 'activated'}); } deactivateStaff(id: string): Observable { return this.http.post(`${environment.cicCacheUrl}/staff/${id}`, {status: 'deactivated'}); } changeStaffType(id: string, type: string): Observable { return this.http.post(`${environment.cicCacheUrl}/staff/${id}`, {accountType: type}); } getAccountDetailsFromMeta(userKey: string): Observable { return this.http.get(`${environment.cicMetaUrl}/${userKey}`, { headers: this.headers }); } getUser(userKey: string): any { return this.http.get(`${environment.cicMetaUrl}/${userKey}`, { headers: this.headers }).pipe(first()).subscribe(async res => { return Envelope.fromJSON(JSON.stringify(res)).unwrap(); }); } wrap(syncable: Syncable, signer: Signer): Promise { return new Promise(async (whohoo, doh) => { syncable.setSigner(signer); syncable.onwrap = async (env) => { if (env === undefined) { doh(); return; } whohoo(env); }; await syncable.sign(); }); } async loadAccounts(limit: number, offset: number = 0): Promise { this.resetAccountsList(); const accountIndexAddress = await this.registry.addressOf('AccountRegistry'); const accountIndexQuery = new AccountIndex(accountIndexAddress); const accountAddresses = await accountIndexQuery.last(await accountIndexQuery.totalAccounts()); for (const accountAddress of accountAddresses.slice(offset, offset + limit)) { this.getAccountDetailsFromMeta(await User.toKey(accountAddress)).pipe(first()).subscribe(res => { const account = Envelope.fromJSON(JSON.stringify(res)).unwrap(); this.accountsMeta.push(account); const accountInfo = account.m.data; accountInfo.vcard = vCard.parse(atob(accountInfo.vcard)); this.accounts.unshift(accountInfo); if (this.accounts.length > limit) { this.accounts.length = limit; } this.accountsList.next(this.accounts); }); } } resetAccountsList(): void { this.accounts = []; this.accountsList.next(this.accounts); } }