File

src/app/_services/user.service.ts

Index

Properties
Methods

Constructor

constructor(httpClient: HttpClient, loggingService: LoggingService, tokenService: TokenService, authService: AuthService)
Parameters :
Name Type Optional
httpClient HttpClient No
loggingService LoggingService No
tokenService TokenService No
authService AuthService No

Methods

addAccount
addAccount(account: AccountDetails, cacheSize: number)
Parameters :
Name Type Optional
account AccountDetails No
cacheSize number No
Returns : void
approveAction
approveAction(id: string)
Parameters :
Name Type Optional
id string No
Returns : Observable<any>
Async changeAccountInfo
changeAccountInfo(address: string, name: string, phoneNumber: string, age: string, type: string, bio: string, gender: string, businessCategory: string, userLocation: string, location: string, locationType: string)
Parameters :
Name Type Optional
address string No
name string No
phoneNumber string No
age string No
type string No
bio string No
gender string No
businessCategory string No
userLocation string No
location string No
locationType string No
Returns : Promise<any>
Async getAccountByAddress
getAccountByAddress(accountAddress: string, limit: number)
Parameters :
Name Type Optional Default value
accountAddress string No
limit number No 100
Async getAccountByPhone
getAccountByPhone(phoneNumber: string, limit: number)
Parameters :
Name Type Optional Default value
phoneNumber string No
limit number No 100
getAccountDetailsFromMeta
getAccountDetailsFromMeta(userKey: string)
Parameters :
Name Type Optional
userKey string No
Returns : Observable<any>
getAccountStatus
getAccountStatus(phone: string)
Parameters :
Name Type Optional
phone string No
Returns : Observable<any>
getAccountTypes
getAccountTypes()
Returns : Observable<any>
getActionById
getActionById(id: string)
Parameters :
Name Type Optional
id string No
Returns : Observable<any>
getActions
getActions()
Returns : void
getCategories
getCategories()
Returns : void
getCategoryByProduct
getCategoryByProduct(product: string, categories: object)
Parameters :
Name Type Optional
product string No
categories object No
Returns : string
getGenders
getGenders()
Returns : Observable<any>
getLockedAccounts
getLockedAccounts(offset: number, limit: number)
Parameters :
Name Type Optional
offset number No
limit number No
Returns : Observable<any>
getTransactionTypes
getTransactionTypes()
Returns : Observable<any>
Async init
init()
Returns : Promise<void>
Async loadAccounts
loadAccounts(limit: number, offset: number)
Parameters :
Name Type Optional Default value
limit number No 100
offset number No 0
Returns : Promise<void>
resetAccountsList
resetAccountsList()
Returns : void
resetPin
resetPin(phone: string)
Parameters :
Name Type Optional
phone string No
Returns : Observable<any>
revokeAction
revokeAction(id: string)
Parameters :
Name Type Optional
id string No
Returns : Observable<any>
searchAccountByName
searchAccountByName(name: string)
Parameters :
Name Type Optional
name string No
Returns : any
Async updateMeta
updateMeta(syncableAccount: Syncable, accountKey: string, headers: HttpHeaders)
Parameters :
Name Type Optional
syncableAccount Syncable No
accountKey string No
headers HttpHeaders No
Returns : Promise<any>
wrap
wrap(syncable: Syncable, signer: Signer)
Parameters :
Name Type Optional
syncable Syncable No
signer Signer No
Returns : Promise<Envelope>

Properties

accounts
Type : Array<AccountDetails>
Default value : []
Private accountsList
Type : BehaviorSubject<Array<AccountDetails>>
Default value : new BehaviorSubject< Array<AccountDetails> >(this.accounts)
accountsSubject
Type : Observable<Array<AccountDetails>>
Default value : this.accountsList.asObservable()
actions
Type : Array<any>
Default value : []
Private actionsList
Type : BehaviorSubject<any>
Default value : new BehaviorSubject<any>(this.actions)
actionsSubject
Type : Observable<Array<any>>
Default value : this.actionsList.asObservable()
categories
Type : object
Default value : {}
Private categoriesList
Type : BehaviorSubject<object>
Default value : new BehaviorSubject<object>(this.categories)
categoriesSubject
Type : Observable<object>
Default value : this.categoriesList.asObservable()
headers
Type : HttpHeaders
Default value : new HttpHeaders({ 'x-cic-automerge': 'client' })
keystore
Type : MutableKeyStore
registry
Type : CICRegistry
signer
Type : Signer
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { environment } from '@src/environments/environment';
import { first } from 'rxjs/operators';
import { ArgPair, Envelope, Phone, Syncable, User } from 'cic-client-meta';
import { AccountDetails } from '@app/_models';
import { LoggingService } from '@app/_services/logging.service';
import { TokenService } from '@app/_services/token.service';
import { AccountIndex } from '@app/_eth';
import { MutableKeyStore, PGPSigner, Signer } from '@app/_pgp';
import { RegistryService } from '@app/_services/registry.service';
import { CICRegistry } from '@cicnet/cic-client';
import { AuthService } from '@app/_services/auth.service';
import { personValidation, updateSyncable, vcardValidation } from '@app/_helpers';
import { add0x } from '@src/assets/js/ethtx/dist/hex';
import { KeystoreService } from '@app/_services/keystore.service';
const vCard = require('vcard-parser');

@Injectable({
  providedIn: 'root',
})
export class UserService {
  headers: HttpHeaders = new HttpHeaders({ 'x-cic-automerge': 'client' });
  keystore: MutableKeyStore;
  signer: Signer;
  registry: CICRegistry;

  accounts: Array<AccountDetails> = [];
  private accountsList: BehaviorSubject<Array<AccountDetails>> = new BehaviorSubject<
    Array<AccountDetails>
  >(this.accounts);
  accountsSubject: Observable<Array<AccountDetails>> = this.accountsList.asObservable();

  actions: Array<any> = [];
  private actionsList: BehaviorSubject<any> = new BehaviorSubject<any>(this.actions);
  actionsSubject: Observable<Array<any>> = this.actionsList.asObservable();

  categories: object = {};
  private categoriesList: BehaviorSubject<object> = new BehaviorSubject<object>(this.categories);
  categoriesSubject: Observable<object> = this.categoriesList.asObservable();

  constructor(
    private httpClient: HttpClient,
    private loggingService: LoggingService,
    private tokenService: TokenService,
    private authService: AuthService
  ) {}

  async init(): Promise<void> {
    await this.authService.init();
    await this.tokenService.init();
    this.keystore = await KeystoreService.getKeystore();
    this.signer = new PGPSigner(this.keystore);
    this.registry = await RegistryService.getRegistry();
  }

  resetPin(phone: string): Observable<any> {
    const params: HttpParams = new HttpParams().set('phoneNumber', phone);
    return this.httpClient.put(`${environment.cicUssdUrl}/pin`, { params });
  }

  getAccountStatus(phone: string): Observable<any> {
    const params: HttpParams = new HttpParams().set('phoneNumber', phone);
    return this.httpClient.get(`${environment.cicUssdUrl}/pin`, { params });
  }

  getLockedAccounts(offset: number, limit: number): Observable<any> {
    return this.httpClient.get(`${environment.cicUssdUrl}/accounts/locked/${offset}/${limit}`);
  }

  async changeAccountInfo(
    address: string,
    name: string,
    phoneNumber: string,
    age: string,
    type: string,
    bio: string,
    gender: string,
    businessCategory: string,
    userLocation: string,
    location: string,
    locationType: string
  ): Promise<any> {
    const accountInfo: any = {
      vcard: {
        fn: [{}],
        n: [{}],
        tel: [{}],
      },
      location: {},
    };
    if (name) {
      accountInfo.vcard.fn[0].value = name;
      accountInfo.vcard.n[0].value = name.split(' ');
    }
    if (phoneNumber) {
      accountInfo.vcard.tel[0].value = phoneNumber;
    }
    if (bio) {
      accountInfo.products = [bio];
    }
    if (gender) {
      accountInfo.gender = gender;
    }
    if (age) {
      accountInfo.age = age;
    }
    if (type) {
      accountInfo.type = type;
    }
    if (businessCategory) {
      accountInfo.category = businessCategory;
    }
    if (location) {
      accountInfo.location.area = location;
    }
    if (userLocation) {
      accountInfo.location.area_name = userLocation;
    }
    if (locationType) {
      accountInfo.location.area_type = locationType;
    }
    await vcardValidation(accountInfo.vcard);
    accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
    const accountKey: string = await User.toKey(address);
    this.getAccountDetailsFromMeta(accountKey)
      .pipe(first())
      .subscribe(
        async (res) => {
          const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
          const update: Array<ArgPair> = [];
          for (const prop of Object.keys(accountInfo)) {
            update.push(new ArgPair(prop, accountInfo[prop]));
          }
          updateSyncable(update, 'client-branch', syncableAccount);
          await personValidation(syncableAccount.m.data);
          await this.updateMeta(syncableAccount, accountKey, this.headers);
        },
        async (error) => {
          this.loggingService.sendErrorLevelMessage(
            'Cannot find account info in meta service',
            this,
            { error }
          );
          const syncableAccount: Syncable = new Syncable(accountKey, accountInfo);
          await this.updateMeta(syncableAccount, accountKey, this.headers);
        }
      );
    return accountKey;
  }

  async updateMeta(
    syncableAccount: Syncable,
    accountKey: string,
    headers: HttpHeaders
  ): Promise<any> {
    const envelope: Envelope = await this.wrap(syncableAccount, this.signer);
    const reqBody: string = envelope.toJSON();
    this.httpClient
      .put(`${environment.cicMetaUrl}/${accountKey}`, reqBody, { headers })
      .pipe(first())
      .subscribe((res) => {
        this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
      });
  }

  getActions(): void {
    this.httpClient
      .get(`${environment.cicCacheUrl}/actions`)
      .pipe(first())
      .subscribe((res) => this.actionsList.next(res));
  }

  getActionById(id: string): Observable<any> {
    return this.httpClient.get(`${environment.cicCacheUrl}/actions/${id}`);
  }

  approveAction(id: string): Observable<any> {
    return this.httpClient.post(`${environment.cicCacheUrl}/actions/${id}`, { approval: true });
  }

  revokeAction(id: string): Observable<any> {
    return this.httpClient.post(`${environment.cicCacheUrl}/actions/${id}`, { approval: false });
  }

  getAccountDetailsFromMeta(userKey: string): Observable<any> {
    return this.httpClient.get(`${environment.cicMetaUrl}/${userKey}`, { headers: this.headers });
  }

  wrap(syncable: Syncable, signer: Signer): Promise<Envelope> {
    return new Promise<Envelope>(async (resolve, reject) => {
      syncable.setSigner(signer);
      syncable.onwrap = async (env) => {
        if (env === undefined) {
          reject();
          return;
        }
        resolve(env);
      };
      await syncable.sign();
    });
  }

  async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> {
    this.resetAccountsList();
    const accountIndexAddress: string = await this.registry.getContractAddressByName(
      'AccountRegistry'
    );
    const accountIndexQuery = new AccountIndex(accountIndexAddress);
    const accountAddresses: Array<string> = await accountIndexQuery.last(limit);
    this.loggingService.sendInfoLevelMessage(accountAddresses);
    for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
      await this.getAccountByAddress(accountAddress, limit);
    }
  }

  async getAccountByAddress(
    accountAddress: string,
    limit: number = 100
  ): Promise<Observable<AccountDetails>> {
    const accountSubject: Subject<any> = new Subject<any>();
    this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress)))
      .pipe(first())
      .subscribe(async (res) => {
        const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
        const accountInfo = account.m.data;
        await personValidation(accountInfo);
        this.tokenService.load.subscribe(async (status: boolean) => {
          if (status) {
            accountInfo.balance = await this.tokenService.getTokenBalance(
              accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
            );
          }
        });
        accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
        await vcardValidation(accountInfo.vcard);
        this.addAccount(accountInfo, limit);
        accountSubject.next(accountInfo);
      });
    return accountSubject.asObservable();
  }

  async getAccountByPhone(
    phoneNumber: string,
    limit: number = 100
  ): Promise<Observable<AccountDetails>> {
    const accountSubject: Subject<any> = new Subject<any>();
    this.getAccountDetailsFromMeta(await Phone.toKey(phoneNumber))
      .pipe(first())
      .subscribe(async (res) => {
        const response: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
        const address: string = response.m.data;
        const account: Observable<AccountDetails> = await this.getAccountByAddress(address, limit);
        account.subscribe((result) => {
          accountSubject.next(result);
        });
      });
    return accountSubject.asObservable();
  }

  resetAccountsList(): void {
    this.accounts = [];
    this.accountsList.next(this.accounts);
  }

  searchAccountByName(name: string): any {
    return;
  }

  getCategories(): void {
    this.httpClient
      .get(`${environment.cicMetaUrl}/categories`)
      .pipe(first())
      .subscribe((res: object) => this.categoriesList.next(res));
  }

  getCategoryByProduct(product: string, categories: object): string {
    const keywords = product.toLowerCase().split(' ');
    for (const keyword of keywords) {
      const queriedCategory: string = Object.keys(categories).find((key) =>
        categories[key].includes(keyword)
      );
      if (queriedCategory) {
        return queriedCategory;
      }
    }
  }

  getAccountTypes(): Observable<any> {
    return this.httpClient.get(`${environment.cicMetaUrl}/accounttypes`);
  }

  getTransactionTypes(): Observable<any> {
    return this.httpClient.get(`${environment.cicMetaUrl}/transactiontypes`);
  }

  getGenders(): Observable<any> {
    return this.httpClient.get(`${environment.cicMetaUrl}/genders`);
  }

  addAccount(account: AccountDetails, cacheSize: number): void {
    const savedIndex = this.accounts.findIndex(
      (acc) =>
        acc.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0] ===
        account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
    );
    if (savedIndex === 0) {
      return;
    }
    if (savedIndex > 0) {
      this.accounts.splice(savedIndex, 1);
    }
    this.accounts.unshift(account);
    if (this.accounts.length > cacheSize) {
      this.accounts.length = Math.min(this.accounts.length, cacheSize);
    }
    this.accountsList.next(this.accounts);
  }
}

result-matching ""

    No results matching ""