Skip to content
This repository has been archived by the owner on Jul 7, 2021. It is now read-only.

feat(profiles): flag contacts with types like wallets #495

Merged
merged 9 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions packages/platform-sdk-profiles/__tests__/env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,7 @@ it("should create a profile with data and persist it when instructed to do so",
const profile = subject.profiles().create("John Doe");

// Create a Contact
profile.contacts().create({
name: "Jane Doe",
addresses: [{ coin: "Ethereum", network: "testnet", address: "TESTNET-ADDRESS" }],
});
profile.contacts().create("Jane Doe");

// Create a Wallet
await profile.wallets().import(identity.mnemonic, ARK, "devnet");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,68 @@
import "jest-extended";
import nock from "nock";

import { ARK } from "@arkecosystem/platform-sdk-ark";

import { ContactRepository } from "../../src/repositories/contact-repository";
import { Profile } from "../../src/profile";
import { Wallet } from "../../src/wallet";
import { container } from "../../src/container";
import { Identifiers } from "../../src/contracts";
import { HttpClient } from "../stubs/client";
import { identity } from "../__fixtures__/identity";

let subject: ContactRepository;

const john = {
name: "John Doe",
addresses: [{ coin: "Bitcoin", network: "livenet", address: "LIVENET-ADDRESS" }],
};
const name = "John Doe";
const addr = { name: "JDB", coin: "ARK", network: "devnet", address: "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib" };

let walletARK: Wallet;
beforeEach(async () => {
nock.cleanAll();

nock(/.+/)
.get("/api/node/configuration")
.reply(200, require("../__fixtures__/client/configuration.json"))
.get("/api/node/configuration/crypto")
.reply(200, require("../__fixtures__/client/cryptoConfiguration.json"))
.get("/api/node/syncing")
.reply(200, require("../__fixtures__/client/syncing.json"))
.get("/api/wallets/D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib")
.reply(200, require("../__fixtures__/client/wallet.json"))
.persist();

container.set(Identifiers.HttpClient, new HttpClient());

const jane = {
name: "Jane Doe",
addresses: [{ coin: "Ethereum", network: "testnet", address: "TESTNET-ADDRESS" }],
};
const profile = new Profile("profile-id", "John Doe");
walletARK = await profile.wallets().import(identity.mnemonic, ARK, "devnet");

beforeEach(() => {
subject = new ContactRepository(new Profile("profile-id", "John Doe"));
subject = new ContactRepository(profile);

subject.flush();
});

beforeAll(() => nock.disableNetConnect());

test("ContactRepository#create", () => {
expect(subject.keys()).toHaveLength(0);

subject.create(john);
subject.create(name);

expect(subject.keys()).toHaveLength(1);

subject.create(jane);

expect(subject.keys()).toHaveLength(2);
});

test("ContactRepository#find", () => {
expect(() => subject.findById("invalid")).toThrowError("Failed to find");

const contact = subject.create(john);
const contact = subject.create(name);

expect(subject.findById(contact.id())).toBeObject();
});

test("ContactRepository#update", () => {
expect(() => subject.update("invalid", { name: "Jane Doe" })).toThrowError("Failed to find");

const contact = subject.create(john);
const contact = subject.create(name);

subject.update(contact.id(), { name: "Jane Doe" });

Expand All @@ -54,45 +72,38 @@ test("ContactRepository#update", () => {
test("ContactRepository#forget", () => {
expect(() => subject.forget("invalid")).toThrowError("Failed to find");

const contact = subject.create(john);
const contact = subject.create(name);

subject.forget(contact.id());

expect(() => subject.findById(contact.id())).toThrowError("Failed to find");
});

test("ContactRepository#findByAddress", () => {
subject.create(john);
subject.create(jane);
test("ContactRepository#findByAddress", async () => {
const wallet = await (await subject.create(name)).addresses().create(addr);

expect(subject.findByAddress(john.addresses[0].address)).toHaveLength(1);
expect(subject.findByAddress(jane.addresses[0].address)).toHaveLength(1);
expect(subject.findByAddress(wallet.address())).toHaveLength(1);
expect(subject.findByAddress("invalid")).toHaveLength(0);
});

test("ContactRepository#findByCoin", () => {
subject.create(john);
subject.create(jane);
test("ContactRepository#findByCoin", async () => {
const wallet = await (await subject.create(name)).addresses().create(addr);

expect(subject.findByCoin(john.addresses[0].coin)).toHaveLength(1);
expect(subject.findByCoin(jane.addresses[0].coin)).toHaveLength(1);
expect(subject.findByCoin(wallet.coin())).toHaveLength(1);
expect(subject.findByCoin("invalid")).toHaveLength(0);
});

test("ContactRepository#findByNetwork", () => {
subject.create(john);
subject.create(jane);
test("ContactRepository#findByNetwork", async () => {
const wallet = await (await subject.create(name)).addresses().create(addr);

expect(subject.findByNetwork(john.addresses[0].network)).toHaveLength(1);
expect(subject.findByNetwork(jane.addresses[0].network)).toHaveLength(1);
expect(subject.findByNetwork(wallet.network())).toHaveLength(1);
expect(subject.findByNetwork("invalid")).toHaveLength(0);
});

test("ContactRepository#flush", () => {
subject.create(john);
subject.create(jane);
test("ContactRepository#flush", async () => {
const wallet = await (await subject.create(name)).addresses().create(addr);

expect(subject.keys()).toHaveLength(2);
expect(subject.keys()).toHaveLength(1);

subject.flush();

Expand Down
4 changes: 2 additions & 2 deletions packages/platform-sdk-profiles/__tests__/stubs/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import got from "got";

export class HttpClient implements Contracts.HttpClient {
public async get(path: string, searchParams = {}): Promise<Record<string, any>> {
return got.get(path, { searchParams }).json();
return got.get(path, { searchParams, timeout: 1000 }).json();
}

public async post(path: string, body, headers = {}) {
return got.post(path, { body: JSON.stringify(body), headers }).json();
return got.post(path, { body: JSON.stringify(body), headers, timeout: 1000 }).json();
}
}
34 changes: 33 additions & 1 deletion packages/platform-sdk-profiles/src/contact-address.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Contracts } from "@arkecosystem/platform-sdk";

import { Avatar } from "./avatar";
import { Profile } from "./profile";
import { Wallet } from "./wallet";

export interface ContactAddressProps {
id: string;
Expand All @@ -10,9 +14,21 @@ export interface ContactAddressProps {

export class ContactAddress {
readonly #data: ContactAddressProps;
readonly #wallet: Contracts.WalletData;

public constructor(data: ContactAddressProps) {
private constructor(data: ContactAddressProps, wallet: Contracts.WalletData) {
this.#data = data;
this.#wallet = wallet;
}

public static async make(data: ContactAddressProps, profile: Profile): Promise<ContactAddress> {
const wallet: Wallet = profile.wallets().findByCoinWithNetwork(data.coin, data.network)[0];

if (!wallet) {
throw new Error(`This profile does not contain any wallets for ${data.coin}/${data.network}.`);
}

return new ContactAddress(data, await wallet.wallet(data.address));
}

public id(): string {
Expand All @@ -39,6 +55,22 @@ export class ContactAddress {
return Avatar.make(this.#data.address);
}

public isDelegate(): boolean {
return this.#wallet.isDelegate();
}

public isKnown(): boolean {
return this.#wallet.isKnown();
}

public isMultiSignature(): boolean {
return this.#wallet.isMultiSignature();
}

public isSecondSignature(): boolean {
return this.#wallet.isSecondSignature();
}

public toObject(): ContactAddressProps {
return {
id: this.id(),
Expand Down
18 changes: 11 additions & 7 deletions packages/platform-sdk-profiles/src/contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ export class Contact {
#addresses: ContactAddressRepository;
#starred: boolean;

public constructor({ id, name, starred, addresses }: ContactStruct, profile: Profile) {
public constructor({ id, name, starred }: ContactStruct, profile: Profile) {
this.#profile = profile;

this.#id = id;
this.#name = name;
this.#starred = starred;

this.#addresses = new ContactAddressRepository(this.#profile);
}

if (addresses) {
this.#addresses.fill(addresses);
}
public async restore(addresses: object[]): Promise<void> {
await this.#addresses.fill(addresses);
}

public id(): string {
Expand All @@ -32,20 +32,24 @@ export class Contact {
return this.#name;
}

public addresses(): ContactAddressRepository {
return this.#addresses;
}

public isStarred(): boolean {
return this.#starred;
}

public addresses(): ContactAddressRepository {
return this.#addresses;
public toggleStarred(): void {
this.#starred = !this.isStarred();
}

public toObject(): ContactStruct {
return {
id: this.id(),
name: this.name(),
starred: this.isStarred(),
addresses: this.addresses().toObject(),
addresses: this.addresses().toArray(),
};
}
}
19 changes: 9 additions & 10 deletions packages/platform-sdk-profiles/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,15 @@ export class Environment {
object({
id: string().required(),
name: string().required(),
addresses: array()
.of(
object({
coin: string().required(),
network: string().required(),
address: string().required(),
avatar: string().required(),
}).noUnknown(),
)
.required(),
addresses: array().of(
object({
id: string().required(),
coin: string().required(),
network: string().required(),
name: string().required(),
address: string().required(),
}).noUnknown(),
),
starred: boolean().required(),
}).noUnknown(),
),
Expand Down
4 changes: 2 additions & 2 deletions packages/platform-sdk-profiles/src/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { Wallet } from "./wallet";
export class Profile {
#contactRepository!: ContactRepository;
#walletRepository!: WalletRepository;
#notificationRepository!: NotificationRepository;
#dataRepository!: DataRepository;
#notificationRepository!: NotificationRepository;
#settingRepository!: SettingRepository;

#id!: string;
Expand All @@ -25,8 +25,8 @@ export class Profile {
this.#id = id;
this.#name = name;
this.#avatar = Avatar.make(id);
this.#contactRepository = new ContactRepository(this);
this.#walletRepository = new WalletRepository(this);
this.#contactRepository = new ContactRepository(this);
this.#notificationRepository = new NotificationRepository();
this.#dataRepository = new DataRepository();
this.#settingRepository = new SettingRepository(Object.values(ProfileSetting));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,18 @@ export class ContactAddressRepository {
}

public async create(data: ContactAddressInput): Promise<ContactAddress> {
// Check if there is a wallet. This will throw if none is found!
const wallet: Wallet = this.#profile.wallets().findByCoinWithNetwork(data.coin, data.network)[0];
await wallet.wallet(data.address);

// Create the address and store it
const id: string = uuidv4();

const address: ContactAddress = new ContactAddress({ id, ...data });
const address: ContactAddress = await ContactAddress.make({ id, ...data }, this.#profile);

this.#data.set(id, address);

return address;
}

public fill(addresses: object): void {
for (const [id, address] of Object.entries(addresses)) {
this.#data.set(id, new ContactAddress(address));
public async fill(addresses: any[]): Promise<void> {
for (const address of addresses) {
this.#data.set(address.id, await ContactAddress.make(address, this.#profile));
}
}

Expand Down Expand Up @@ -110,11 +105,11 @@ export class ContactAddressRepository {
return this.#data.count();
}

public toObject(): Record<string, object> {
const result: Record<string, object> = {};
public toArray(): object[] {
const result: object[] = [];

for (const [id, address] of Object.entries(this.#data.all())) {
result[id] = address.toObject();
for (const address of this.values()) {
result.push(address.toObject());
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ export class ContactRepository {
return contact;
}

public fill(contacts: object): void {
public async fill(contacts: object): Promise<void> {
for (const [id, contact] of Object.entries(contacts)) {
this.#data.set(id, new Contact(contact, this.#profile));
const instance: Contact = new Contact(contact, this.#profile);

await instance.restore(contact.addresses);

this.#data.set(id, instance);
}
}

Expand Down Expand Up @@ -89,7 +93,7 @@ export class ContactRepository {
const match: ContactAddress | undefined = contact
.addresses()
.values()
.find((address: ContactAddress) => address[column] === value);
.find((address: ContactAddress) => address[column]() === value);

if (match) {
result.push(contact);
Expand Down
Loading