(); // Currency/FlowNode Id
+
+ foreach (var transaction in transactions)
+ {
+ switch (transaction.Type)
+ {
+ case TransactionType.In:
+ {
+ if (lastBuckets.ContainsKey(transaction.InCurrency))
+ {
+ // Add Amount to new Bucket
+ var sourceNode = nodes.Single(n => n.DateTime == transaction.DateTime && n.Amount == transaction.InAmount);
+
+ var oldNode = nodes.Single(n => n.Id == lastBuckets[transaction.InCurrency]);
+ var newNode = new FlowNode(transaction.DateTime, transaction.InAmount + oldNode.Amount, transaction.InCurrency, exchange.Id, Guid.Empty);
+ nodes.Add(newNode);
+ var link1 = new FlowLink(transaction.DateTime, oldNode.Amount, transaction.InCurrency, oldNode.Id, newNode.Id, exchange.Id);
+ var link2 = new FlowLink(transaction.DateTime, transaction.InAmount, transaction.InCurrency, sourceNode.Id, newNode.Id, exchange.Id, "In");
+ links.Add(link1);
+ links.Add(link2);
+ lastBuckets[transaction.InCurrency] = newNode.Id;
+
+ }
+ else
+ {
+ var sourceNode = nodes.Single(n => n.TransactionId == transaction.Id);
+ var node = new FlowNode(transaction.DateTime, transaction.InAmount, transaction.InCurrency, exchange.Id, transaction.Id);
+ nodes.Add(node);
+
+ var link = new FlowLink(transaction.DateTime, transaction.InAmount, transaction.InCurrency, sourceNode.Id, node.Id, exchange.Id, "In");
+ links.Add(link);
+ lastBuckets.Add(transaction.InCurrency, node.Id);
+ }
+ }
+
+ break;
+
+ case TransactionType.Trade:
+ if (lastBuckets.ContainsKey(transaction.BuyCurrency))
+ {
+ // Buy Bucket already exists
+ var buyBucketNode = nodes.Single(n => n.Id == lastBuckets[transaction.BuyCurrency]);
+ var prevNode = nodes.Single(n => n.Id == lastBuckets[transaction.SellCurrency]);
+ var restNode = new FlowNode(transaction.DateTime, prevNode.Amount - transaction.SellAmount, transaction.SellCurrency, exchange.Id, transaction.Id);
+ var newBuyBucketNode = new FlowNode(transaction.DateTime, buyBucketNode.Amount + transaction.BuyAmount, buyBucketNode.Currency, exchange.Id, transaction.Id);
+
+ // Calculate fee
+ if (transaction.FeeCurrency == prevNode.Currency)
+ {
+ restNode.Amount -= transaction.FeeAmount;
+ }
+ else if (transaction.FeeCurrency == newBuyBucketNode.Currency)
+ {
+ newBuyBucketNode.Amount -= transaction.FeeAmount;
+ }
+ else
+ {
+ throw new NotImplementedException("Transaction Fee could not be added");
+ }
+
+ var linkToNewBuyBucket = new FlowLink(transaction.DateTime, transaction.BuyAmount, transaction.BuyCurrency, prevNode.Id, newBuyBucketNode.Id, exchange.Id, $"Trade {Math.Round(transaction.BuyAmount, 2)} {transaction.BuyCurrency} for {Math.Round(transaction.SellAmount, 2)} {transaction.SellCurrency}");
+ var linkToNewBucket = new FlowLink(transaction.DateTime, buyBucketNode.Amount, buyBucketNode.Currency, buyBucketNode.Id, newBuyBucketNode.Id, exchange.Id);
+ var linkToNewRestBucket = new FlowLink(transaction.DateTime, prevNode.Amount - transaction.SellAmount, transaction.SellCurrency, prevNode.Id, restNode.Id, exchange.Id);
+
+ // Add data
+ nodes.Add(restNode);
+ nodes.Add(newBuyBucketNode);
+ links.Add(linkToNewBuyBucket);
+ links.Add(linkToNewBucket);
+ links.Add(linkToNewRestBucket);
+
+ // Set new Buckets
+ lastBuckets[transaction.BuyCurrency] = newBuyBucketNode.Id;
+ lastBuckets[transaction.SellCurrency] = restNode.Id;
+ }
+ else
+ {
+ // Create new Buy Bucket
+ var prevNode = nodes.Single(n => n.Id == lastBuckets[transaction.SellCurrency]);
+ var buyNode = new FlowNode(transaction.DateTime, transaction.BuyAmount, transaction.BuyCurrency, exchange.Id, transaction.Id);
+ var sellAndRestNode = new FlowNode(transaction.DateTime, prevNode.Amount - transaction.SellAmount, transaction.SellCurrency, exchange.Id, transaction.Id);
+
+ // Calculate fee
+ if (transaction.FeeCurrency == prevNode.Currency)
+ {
+ sellAndRestNode.Amount -= transaction.FeeAmount;
+ }
+ else if (transaction.FeeCurrency == buyNode.Currency)
+ {
+ buyNode.Amount -= transaction.FeeAmount;
+ }
+ else
+ {
+ throw new NotImplementedException("Transaction Fee could not be added");
+ }
+
+
+ // Add Links
+ var buyLink = new FlowLink(transaction.DateTime, transaction.BuyAmount, transaction.BuyCurrency, prevNode.Id, buyNode.Id, exchange.Id, $"Trade {Math.Round(transaction.BuyAmount, 2)} {transaction.BuyCurrency} for {Math.Round(transaction.SellAmount, 2)} {transaction.SellCurrency}");
+ var sellAndRestLink = new FlowLink(transaction.DateTime, prevNode.Amount - transaction.SellAmount, transaction.SellCurrency, prevNode.Id, sellAndRestNode.Id, exchange.Id);
+
+ // Add to Dictionaries
+ links.Add(buyLink);
+ links.Add(sellAndRestLink);
+ nodes.Add(buyNode);
+ nodes.Add(sellAndRestNode);
+
+ // Set new Buckets
+ lastBuckets[transaction.BuyCurrency] = buyNode.Id;
+ lastBuckets[transaction.SellCurrency] = sellAndRestNode.Id;
+ }
+ break;
+
+ case TransactionType.Out:
+ var previousNode = nodes.Single(n => n.Id == lastBuckets[transaction.OutCurrency]);
+
+ var outNode = nodes.Single(n => n.TransactionId == transaction.Id);
+ var nextNode = new FlowNode(transaction.DateTime, previousNode.Amount - outNode.Amount, transaction.OutCurrency, exchange.Id, Guid.Empty);
+ nodes.Add(nextNode);
+
+ var linkPreviousOut = new FlowLink(transaction.DateTime, transaction.OutAmount, transaction.OutCurrency, previousNode.Id, outNode.Id, exchange.Id, "Out");
+ var linkPreviousNext = new FlowLink(transaction.DateTime, nextNode.Amount, transaction.OutCurrency, previousNode.Id, nextNode.Id, exchange.Id);
+ links.Add(linkPreviousOut);
+ links.Add(linkPreviousNext);
+ lastBuckets[transaction.OutCurrency] = nextNode.Id;
+
+ break;
+
+ default:
+ throw new ArgumentException($"Transaction Type {transaction.Type} is unknown");
+ }
+ }
+
+
+ allNodes.Add(exchange.Id, nodes);
+ allLinks.Add(exchange.Id, links);
+ }
+
+
+
+ // Save Data
+ foreach (var allNode in allNodes)
+ {
+ foreach (var nodes in allNode.Value)
+ {
+ _context.FlowNodes.Add(nodes);
+ }
+ }
+ foreach (var allLink in allLinks)
+ {
+ foreach (var link in allLink.Value)
+ {
+ _context.FlowLinks.Add(link);
+ }
+ }
+
+ _context.SaveChanges();
+ }
+
class Fiat
{
public decimal Investments { get; set; }
@@ -202,3 +394,6 @@ class Fiat
}
}
+
+
+
diff --git a/CryptoManager/ClientApp/app/app.shared.module.ts b/CryptoManager/ClientApp/app/app.shared.module.ts
index 4821bad..c0ad50f 100644
--- a/CryptoManager/ClientApp/app/app.shared.module.ts
+++ b/CryptoManager/ClientApp/app/app.shared.module.ts
@@ -9,6 +9,9 @@ import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DropdownModule, ButtonModule, DataTableModule, SharedModule, ConfirmDialogModule, ConfirmationService } from 'primeng/primeng';
+import { NgxGraphModule } from '@swimlane/ngx-graph';
+import { NgxChartsModule } from '@swimlane/ngx-charts';
+
import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
@@ -17,49 +20,55 @@ import { ExchangesComponent } from './components/exchanges/exchanges.component';
import { TransactionsComponent } from './components/transactions/transactions.component';
import { FundsComponent } from './components/funds/funds.component';
import { InvestmentsComponent } from './components/investments/investments.component'
+import { FlowComponent } from './components/flow/flow.component'
import { CryptoApiClient } from './services/api-client';
@NgModule({
- declarations: [
- AppComponent,
- NavMenuComponent,
- HomeComponent,
- ExchangesComponent,
- TransactionsComponent,
- FundsComponent,
- InvestmentsComponent
- ],
- imports: [
- CommonModule,
- HttpModule,
- FormsModule,
+ declarations: [
+ AppComponent,
+ NavMenuComponent,
+ HomeComponent,
+ ExchangesComponent,
+ TransactionsComponent,
+ FundsComponent,
+ InvestmentsComponent,
+ FlowComponent
+ ],
+ imports: [
+ CommonModule,
+ HttpModule,
+ FormsModule,
+
+ DropdownModule,
+ ButtonModule,
+ DataTableModule,
+ SharedModule,
+ ConfirmDialogModule,
- DropdownModule,
- ButtonModule,
- DataTableModule,
- SharedModule,
- ConfirmDialogModule,
+ BrowserModule,
+ BrowserAnimationsModule,
+ HttpClientModule,
- BrowserModule,
- BrowserAnimationsModule,
- HttpClientModule,
+ NgxChartsModule,
+ NgxGraphModule,
- RouterModule.forRoot([
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'home', component: HomeComponent },
- { path: 'transactions', component: TransactionsComponent },
- { path: 'funds', component: FundsComponent },
- { path: 'investments', component: InvestmentsComponent },
- { path: 'exchanges', component: ExchangesComponent },
- { path: '**', redirectTo: 'home' }
- ])
- ],
- providers: [
- CryptoApiClient,
+ RouterModule.forRoot([
+ { path: '', redirectTo: 'home', pathMatch: 'full' },
+ { path: 'home', component: HomeComponent },
+ { path: 'transactions', component: TransactionsComponent },
+ { path: 'funds', component: FundsComponent },
+ { path: 'investments', component: InvestmentsComponent },
+ { path: 'exchanges', component: ExchangesComponent },
+ { path: 'flow', component: FlowComponent },
+ { path: '**', redirectTo: 'home' }
+ ])
+ ],
+ providers: [
+ CryptoApiClient,
- ConfirmationService
- ]
+ ConfirmationService
+ ]
})
export class AppModuleShared {
}
diff --git a/CryptoManager/ClientApp/app/components/flow/flow.component.html b/CryptoManager/ClientApp/app/components/flow/flow.component.html
new file mode 100644
index 0000000..336d5ef
--- /dev/null
+++ b/CryptoManager/ClientApp/app/components/flow/flow.component.html
@@ -0,0 +1,57 @@
+Flow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{node.label}}
+
+
+
+
+
+
+
+
+
+ {{link.label}}
+
+
+
+
+
+
+
diff --git a/CryptoManager/ClientApp/app/components/flow/flow.component.scss b/CryptoManager/ClientApp/app/components/flow/flow.component.scss
new file mode 100644
index 0000000..e197108
--- /dev/null
+++ b/CryptoManager/ClientApp/app/components/flow/flow.component.scss
@@ -0,0 +1,3 @@
+.graph .edge .edge-label{
+ fill: black !important;
+}
\ No newline at end of file
diff --git a/CryptoManager/ClientApp/app/components/flow/flow.component.spec.ts b/CryptoManager/ClientApp/app/components/flow/flow.component.spec.ts
new file mode 100644
index 0000000..c627c18
--- /dev/null
+++ b/CryptoManager/ClientApp/app/components/flow/flow.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FlowComponent } from './flow.component';
+
+describe('FlowComponent', () => {
+ let component: FlowComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [FlowComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FlowComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/CryptoManager/ClientApp/app/components/flow/flow.component.ts b/CryptoManager/ClientApp/app/components/flow/flow.component.ts
new file mode 100644
index 0000000..3f5c16f
--- /dev/null
+++ b/CryptoManager/ClientApp/app/components/flow/flow.component.ts
@@ -0,0 +1,133 @@
+import { Component, OnInit } from '@angular/core';
+import * as shape from 'd3-shape';
+import { CryptoApiClient, IExchangeDTO } from '../../services/api-client';
+import { SelectItem } from 'primeng/primeng';
+
+
+@Component({
+ selector: 'app-flow',
+ templateUrl: './flow.component.html',
+ styleUrls: ['./flow.component.scss']
+})
+
+export class FlowComponent implements OnInit {
+
+ exchanges: SelectItem[] = [{ label: 'Select Exchange Plugin', value: null },];
+ selectedExchange: IExchangeDTO;
+
+ constructor(private apiClient: CryptoApiClient) {
+ const nodes: any[] = [];
+ const links: any[] = [];
+ this.hierarchialGraph = { nodes, links };
+
+ //this.apiClient.apiExchangesGet().subscribe(exchanges => {
+ // for (let exchange of exchanges) {
+ // this.exchanges.push(({
+ // label: exchange.exchangeName,
+ // value: exchange.id
+ // }));
+ // }
+ // console.log(this.exchanges);
+ //});
+
+
+ }
+
+
+ ngOnInit() {
+ this.apiClient.apiExchangesGet().subscribe(ex => {
+ for (let entry of ex) {
+ this.exchanges.push({
+ label: entry.exchangeName,
+ value: entry
+ });
+ }
+ });
+
+
+
+
+
+ if (!this.fitContainer) {
+ this.applyDimensions();
+ }
+ }
+
+ exchangeChanged() {
+ const nodes: any[] = [];
+ const links: any[] = [];
+ this.hierarchialGraph = { nodes, links };
+
+ if (this.selectedExchange == null)
+ return;
+
+
+ this.apiClient.apiFlowsNodesGet(String(this.selectedExchange.id)).subscribe(nodes => {
+ for (var i = 0; i < nodes.length; i++) {
+ var label = nodes[i].comment == null
+ ? nodes[i].amount + " " + nodes[i].currency
+ : nodes[i].comment + " " + nodes[i].amount + " " + nodes[i].currency;
+
+
+ this.hierarchialGraph.nodes.push({
+ id: nodes[i].id,
+ label: label
+ });
+
+ }
+ this.hierarchialGraph.nodes = [...this.hierarchialGraph.nodes];
+
+ this.apiClient.apiFlowsLinksGet(String(this.selectedExchange.id)).subscribe(links => {
+ for (var i = 0; i < links.length; i++) {
+
+ this.hierarchialGraph.links.push({
+ source: links[i].flowNodeSource,
+ target: links[i].flowNodeTarget,
+ label: links[i].comment
+ });
+
+ }
+
+ this.hierarchialGraph.links = [...this.hierarchialGraph.links];
+ });
+ });
+ }
+
+ applyDimensions() {
+ this.view = [this.width, this.height];
+ }
+
+
+
+
+ colorScheme = {
+ name: 'picnic',
+ selectable: false,
+ group: 'Ordinal',
+ domain: [
+ '#FAC51D', '#66BD6D', '#FAA026', '#29BB9C', '#E96B56', '#55ACD2', '#B7332F', '#2C83C9', '#9166B8', '#92E7E8'
+ ]
+ };
+ schemeType: string = 'ordinal';
+
+ curveType: string = 'Linear';
+ curve: any = shape.curveBundle.beta(1);
+
+
+
+ hierarchialGraph: { links: any[], nodes: any[] };
+
+
+ view: any[];
+ width: number = 1200;
+ height: number = 1200;
+ fitContainer: boolean = true;
+ autoZoom: boolean = true;
+
+ // options
+ showLegend = false;
+ orientation: string = 'TB'; // LR, RL, TB, BT
+
+
+}
+
diff --git a/CryptoManager/ClientApp/app/components/navmenu/navmenu.component.html b/CryptoManager/ClientApp/app/components/navmenu/navmenu.component.html
index 279cc2c..711f45e 100644
--- a/CryptoManager/ClientApp/app/components/navmenu/navmenu.component.html
+++ b/CryptoManager/ClientApp/app/components/navmenu/navmenu.component.html
@@ -42,6 +42,12 @@
+
+
+ Flow
+
+
+
Recalculate
@@ -52,12 +58,12 @@
1" class="badge">{{backgroundTasks}} Background tasks running
{{backgroundTasks}} Background task running
-
+
-
+
diff --git a/CryptoManager/ClientApp/app/services/api-client.ts b/CryptoManager/ClientApp/app/services/api-client.ts
index 22516ef..09db8e2 100644
--- a/CryptoManager/ClientApp/app/services/api-client.ts
+++ b/CryptoManager/ClientApp/app/services/api-client.ts
@@ -355,6 +355,126 @@ export class CryptoApiClient {
return Observable.of(null);
}
+ /**
+ * @return Success
+ */
+ apiFlowsNodesGet(exchangeId: string): Observable {
+ let url_ = this.baseUrl + "/api/Flows/Nodes?";
+ if (exchangeId === undefined || exchangeId === null)
+ throw new Error("The parameter 'exchangeId' must be defined and cannot be null.");
+ else
+ url_ += "exchangeId=" + encodeURIComponent("" + exchangeId) + "&";
+ url_ = url_.replace(/[?&]$/, "");
+
+ let options_ : any = {
+ observe: "response",
+ responseType: "blob",
+ headers: new HttpHeaders({
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ })
+ };
+
+ return this.http.request("get", url_, options_).flatMap((response_ : any) => {
+ return this.processApiFlowsNodesGet(response_);
+ }).catch((response_: any) => {
+ if (response_ instanceof HttpResponseBase) {
+ try {
+ return this.processApiFlowsNodesGet(response_);
+ } catch (e) {
+ return >Observable.throw(e);
+ }
+ } else
+ return >Observable.throw(response_);
+ });
+ }
+
+ protected processApiFlowsNodesGet(response: HttpResponseBase): Observable {
+ const status = response.status;
+ const responseBlob =
+ response instanceof HttpResponse ? response.body :
+ response instanceof HttpErrorResponse ? response.error : undefined;
+
+ let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }};
+ if (status === 200) {
+ return blobToText(responseBlob).flatMap(_responseText => {
+ let result200: any = null;
+ let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
+ if (resultData200 && resultData200.constructor === Array) {
+ result200 = [];
+ for (let item of resultData200)
+ result200.push(FlowNodeDTO.fromJS(item));
+ }
+ return Observable.of(result200);
+ });
+ } else if (status !== 200 && status !== 204) {
+ return blobToText(responseBlob).flatMap(_responseText => {
+ return throwException("An unexpected server error occurred.", status, _responseText, _headers);
+ });
+ }
+ return Observable.of(null);
+ }
+
+ /**
+ * @return Success
+ */
+ apiFlowsLinksGet(exchangeId: string): Observable {
+ let url_ = this.baseUrl + "/api/Flows/Links?";
+ if (exchangeId === undefined || exchangeId === null)
+ throw new Error("The parameter 'exchangeId' must be defined and cannot be null.");
+ else
+ url_ += "exchangeId=" + encodeURIComponent("" + exchangeId) + "&";
+ url_ = url_.replace(/[?&]$/, "");
+
+ let options_ : any = {
+ observe: "response",
+ responseType: "blob",
+ headers: new HttpHeaders({
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ })
+ };
+
+ return this.http.request("get", url_, options_).flatMap((response_ : any) => {
+ return this.processApiFlowsLinksGet(response_);
+ }).catch((response_: any) => {
+ if (response_ instanceof HttpResponseBase) {
+ try {
+ return this.processApiFlowsLinksGet(response_);
+ } catch (e) {
+ return >Observable.throw(e);
+ }
+ } else
+ return >Observable.throw(response_);
+ });
+ }
+
+ protected processApiFlowsLinksGet(response: HttpResponseBase): Observable {
+ const status = response.status;
+ const responseBlob =
+ response instanceof HttpResponse ? response.body :
+ response instanceof HttpErrorResponse ? response.error : undefined;
+
+ let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }};
+ if (status === 200) {
+ return blobToText(responseBlob).flatMap(_responseText => {
+ let result200: any = null;
+ let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
+ if (resultData200 && resultData200.constructor === Array) {
+ result200 = [];
+ for (let item of resultData200)
+ result200.push(FlowLink.fromJS(item));
+ }
+ return Observable.of(result200);
+ });
+ } else if (status !== 200 && status !== 204) {
+ return blobToText(responseBlob).flatMap(_responseText => {
+ return throwException("An unexpected server error occurred.", status, _responseText, _headers);
+ });
+ }
+ return Observable.of(null);
+ }
+
/**
* @return Success
*/
@@ -788,6 +908,128 @@ export interface IFiatDTO {
exchangeId?: string | undefined;
}
+export class FlowNodeDTO implements IFlowNodeDTO {
+ id?: string | undefined;
+ dateTime?: Date | undefined;
+ amount?: number | undefined;
+ currency?: string | undefined;
+ exchangeId?: string | undefined;
+ comment?: string | undefined;
+ transactionId?: string | undefined;
+
+ constructor(data?: IFlowNodeDTO) {
+ if (data) {
+ for (var property in data) {
+ if (data.hasOwnProperty(property))
+ (this)[property] = (data)[property];
+ }
+ }
+ }
+
+ init(data?: any) {
+ if (data) {
+ this.id = data["id"];
+ this.dateTime = data["dateTime"] ? new Date(data["dateTime"].toString()) : undefined;
+ this.amount = data["amount"];
+ this.currency = data["currency"];
+ this.exchangeId = data["exchangeId"];
+ this.comment = data["comment"];
+ this.transactionId = data["transactionId"];
+ }
+ }
+
+ static fromJS(data: any): FlowNodeDTO {
+ let result = new FlowNodeDTO();
+ result.init(data);
+ return result;
+ }
+
+ toJSON(data?: any) {
+ data = typeof data === 'object' ? data : {};
+ data["id"] = this.id;
+ data["dateTime"] = this.dateTime ? this.dateTime.toISOString() : undefined;
+ data["amount"] = this.amount;
+ data["currency"] = this.currency;
+ data["exchangeId"] = this.exchangeId;
+ data["comment"] = this.comment;
+ data["transactionId"] = this.transactionId;
+ return data;
+ }
+}
+
+export interface IFlowNodeDTO {
+ id?: string | undefined;
+ dateTime?: Date | undefined;
+ amount?: number | undefined;
+ currency?: string | undefined;
+ exchangeId?: string | undefined;
+ comment?: string | undefined;
+ transactionId?: string | undefined;
+}
+
+export class FlowLink implements IFlowLink {
+ id?: string | undefined;
+ dateTime?: Date | undefined;
+ amount?: number | undefined;
+ currency?: string | undefined;
+ flowNodeSource?: string | undefined;
+ flowNodeTarget?: string | undefined;
+ comment?: string | undefined;
+ exchangeId?: string | undefined;
+
+ constructor(data?: IFlowLink) {
+ if (data) {
+ for (var property in data) {
+ if (data.hasOwnProperty(property))
+ (this)[property] = (data)[property];
+ }
+ }
+ }
+
+ init(data?: any) {
+ if (data) {
+ this.id = data["id"];
+ this.dateTime = data["dateTime"] ? new Date(data["dateTime"].toString()) : undefined;
+ this.amount = data["amount"];
+ this.currency = data["currency"];
+ this.flowNodeSource = data["flowNodeSource"];
+ this.flowNodeTarget = data["flowNodeTarget"];
+ this.comment = data["comment"];
+ this.exchangeId = data["exchangeId"];
+ }
+ }
+
+ static fromJS(data: any): FlowLink {
+ let result = new FlowLink();
+ result.init(data);
+ return result;
+ }
+
+ toJSON(data?: any) {
+ data = typeof data === 'object' ? data : {};
+ data["id"] = this.id;
+ data["dateTime"] = this.dateTime ? this.dateTime.toISOString() : undefined;
+ data["amount"] = this.amount;
+ data["currency"] = this.currency;
+ data["flowNodeSource"] = this.flowNodeSource;
+ data["flowNodeTarget"] = this.flowNodeTarget;
+ data["comment"] = this.comment;
+ data["exchangeId"] = this.exchangeId;
+ return data;
+ }
+}
+
+export interface IFlowLink {
+ id?: string | undefined;
+ dateTime?: Date | undefined;
+ amount?: number | undefined;
+ currency?: string | undefined;
+ flowNodeSource?: string | undefined;
+ flowNodeTarget?: string | undefined;
+ comment?: string | undefined;
+ exchangeId?: string | undefined;
+}
+
export class FundDTO implements IFundDTO {
id?: string | undefined;
currency?: string | undefined;
@@ -1184,6 +1426,7 @@ export enum ExchangeMetaExchangeId {
_2 = 2,
_3 = 3,
_4 = 4,
+ _5 = 5,
}
export enum ExchangeDTOExchange {
@@ -1191,6 +1434,7 @@ export enum ExchangeDTOExchange {
_2 = 2,
_3 = 3,
_4 = 4,
+ _5 = 5,
}
export enum ExchangeId {
@@ -1198,6 +1442,7 @@ export enum ExchangeId {
_2 = 2,
_3 = 3,
_4 = 4,
+ _5 = 5,
}
export enum CryptoTransactionType {
diff --git a/CryptoManager/Controllers/FlowsController.cs b/CryptoManager/Controllers/FlowsController.cs
new file mode 100644
index 0000000..bd9c0ee
--- /dev/null
+++ b/CryptoManager/Controllers/FlowsController.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using AutoMapper;
+using CryptoManager.Models;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Model.DbModels;
+using Model.DTOs;
+
+namespace CryptoManager.Controllers
+{
+ [Produces("application/json")]
+ [Route("api/Flows")]
+ public class FlowsController : Controller
+ {
+ private readonly CryptoContext _context;
+ private readonly IMapper _mapper;
+
+ public FlowsController(CryptoContext context, IMapper mapper)
+ {
+ _context = context;
+ _mapper = mapper;
+ }
+
+ [HttpGet("Nodes")]
+ public async Task> GetNodes(Guid exchangeId)
+ {
+ return await Task.Run(() => _mapper.Map>(_context.FlowNodes.Where(f => f.ExchangeId == exchangeId)));
+ }
+
+ [HttpGet("Links")]
+ public async Task> GetLinks(Guid exchangeId)
+ {
+ var res = await Task.Run(() => _mapper.Map>(_context.FlowLinks.Where(f => f.ExchangeId == exchangeId)));
+ return res;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CryptoManager/CryptoManager.csproj b/CryptoManager/CryptoManager.csproj
index 1c66d5e..a0cb071 100644
--- a/CryptoManager/CryptoManager.csproj
+++ b/CryptoManager/CryptoManager.csproj
@@ -6,7 +6,7 @@
Latest
false
win-x64;osx-x64
- Exe
+
@@ -14,12 +14,12 @@
-
+
-
-
-
-
+
+
+
+
diff --git a/CryptoManager/MappingProfile.cs b/CryptoManager/MappingProfile.cs
index 0ce29a6..0a0ff1b 100644
--- a/CryptoManager/MappingProfile.cs
+++ b/CryptoManager/MappingProfile.cs
@@ -17,6 +17,16 @@ public MappingProfile()
CreateMap();
CreateMap();
+
+ CreateMap()
+ .ForMember(dto => dto.Id,
+ expression => expression.MapFrom(node => node.Id.ToString().Replace("-", string.Empty)));
+
+ CreateMap()
+ .ForMember(dto => dto.FlowNodeSource,
+ expression => expression.MapFrom(link => link.FlowNodeSource.ToString().Replace("-", string.Empty)))
+ .ForMember(dto => dto.FlowNodeTarget,
+ expression => expression.MapFrom(link => link.FlowNodeTarget.ToString().Replace("-", string.Empty)));
}
}
}
diff --git a/CryptoManager/NLog.config b/CryptoManager/NLog.config
index 8e7ffcb..f579242 100644
--- a/CryptoManager/NLog.config
+++ b/CryptoManager/NLog.config
@@ -3,12 +3,12 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="info"
- internalLogFile="c:\temp\internal-nlog.txt">
+ internalLogFile="../log/internal-nlog.txt">
-
+
@@ -25,7 +25,7 @@
-
+
diff --git a/CryptoManager/Startup.cs b/CryptoManager/Startup.cs
index 50c5888..c79226e 100644
--- a/CryptoManager/Startup.cs
+++ b/CryptoManager/Startup.cs
@@ -125,6 +125,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
//BackgroundJob.Enqueue(i => i.ImportAll());
BackgroundJob.Enqueue(c => c.RecalculateAll());
+ //BackgroundJob.Enqueue(c => c.CalculateFlow());
}
}
diff --git a/CryptoManager/package.json b/CryptoManager/package.json
index cd39475..24b5bf8 100644
--- a/CryptoManager/package.json
+++ b/CryptoManager/package.json
@@ -20,6 +20,8 @@
"@angular/router": "^5.0.0",
"@ngtools/webpack": "^1.0.0",
"@types/chai": "^4.0.0",
+ "@types/d3": "^4.12.0",
+ "@types/d3-shape": "^1.2.2",
"@types/jasmine": "^2.0.0",
"@types/webpack-env": "^1.0.0",
"angular2-router-loader": "0.3.5",
@@ -63,6 +65,7 @@
"zone.js": "^0.8.0"
},
"dependencies": {
+ "@swimlane/ngx-graph": "^4.0.2",
"font-awesome": "^4.7.0",
"font-awesome-webpack": "^0.0.5-beta.2",
"primeng": "^5.0.2"
diff --git a/CryptoManager/yarn.lock b/CryptoManager/yarn.lock
index 971d3ca..60abcc0 100644
--- a/CryptoManager/yarn.lock
+++ b/CryptoManager/yarn.lock
@@ -184,10 +184,217 @@
dependencies:
"@angular-devkit/core" "0.0.24"
+"@swimlane/ngx-charts@^7.0.1":
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/@swimlane/ngx-charts/-/ngx-charts-7.0.1.tgz#5b537150086f0d1776921148079e91437224fbef"
+ dependencies:
+ d3-array "^1.2.1"
+ d3-brush "^1.0.4"
+ d3-color "^1.0.3"
+ d3-force "^1.1.0"
+ d3-format "^1.2.0"
+ d3-hierarchy "^1.1.5"
+ d3-interpolate "^1.1.5"
+ d3-scale "^1.0.6"
+ d3-selection "^1.1.0"
+ d3-shape "^1.2.0"
+ d3-time-format "^2.1.0"
+
+"@swimlane/ngx-graph@^4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@swimlane/ngx-graph/-/ngx-graph-4.0.2.tgz#c6899aa3d937af39259fe568c7ea6682a9228e10"
+ dependencies:
+ "@swimlane/ngx-charts" "^7.0.1"
+ "@types/d3-transition" "^1.1.1"
+ d3-selection "^1.2.0"
+ d3-shape "^1.2.0"
+ d3-transition "^1.1.1"
+ dagre "^0.7.4"
+
"@types/chai@^4.0.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.0.tgz#d9008fa4c06f6801f93396d121f0227cd4244ac6"
+"@types/d3-array@*":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-1.2.1.tgz#e489605208d46a1c9d980d2e5772fa9c75d9ec65"
+
+"@types/d3-axis@*":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-1.0.9.tgz#62ce7bc8d04354298cda57f3f1d1f856ad69b89a"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-brush@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-1.0.7.tgz#05c30440f4d537fd23f976b0e6c4ba223001ef45"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-chord@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-1.0.6.tgz#0589eb97a3191f4edaf17b7bde498462890ce1ec"
+
+"@types/d3-collection@*":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-collection/-/d3-collection-1.0.5.tgz#bb1f3aa97cdc8d881645541b9d6cf87edfee9bc3"
+
+"@types/d3-color@*":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.0.5.tgz#cad755f0fc6de7b70fa6e5e08afa81ef4c2248de"
+
+"@types/d3-dispatch@*":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-1.0.5.tgz#f1f9187b538ecb05157569d8dc2f70dfb04f1b52"
+
+"@types/d3-drag@*":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-1.2.0.tgz#5ee6279432c894f85cb72fcda911a959bae11952"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-dsv@*":
+ version "1.0.31"
+ resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-1.0.31.tgz#468302f18ac44db2a3944086388d862503ab9c6c"
+
+"@types/d3-ease@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-1.0.7.tgz#93a301868be9e15061f3d44343b1ab3f8acb6f09"
+
+"@types/d3-force@*":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-1.1.0.tgz#40925ca3512b63bd424f7c9685e1781b5b0a1d7e"
+
+"@types/d3-format@*":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-1.2.1.tgz#9435fb1771d2fbf6a858c93218f4097c9aa396c1"
+
+"@types/d3-geo@*":
+ version "1.9.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-1.9.4.tgz#9cfa573b6702e260b3fec127d88589ca9fc2de1d"
+ dependencies:
+ "@types/geojson" "*"
+
+"@types/d3-hierarchy@*":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.0.tgz#50f1ee052840638035cbdd4acab1fc3470905907"
+
+"@types/d3-interpolate@*":
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.1.6.tgz#64041b15c9c032c348da1b22baabc59fa4d16136"
+ dependencies:
+ "@types/d3-color" "*"
+
+"@types/d3-path@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.6.tgz#c1a7d2dc07b295fdd1c84dabe4404df991b48693"
+
+"@types/d3-polygon@*":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-1.0.5.tgz#35ad54ed84c39d7e9f1252b6535be600be6cace2"
+
+"@types/d3-quadtree@*":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-1.0.5.tgz#1ce1e659eae4530df0cb127f297f1741a367a82e"
+
+"@types/d3-queue@*":
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-queue/-/d3-queue-3.0.5.tgz#3e4cbe2aff61db6a0b2b8c4800299e4ec6acc850"
+
+"@types/d3-random@*":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-1.1.0.tgz#2dd08f1159c70719270e4a7c834af85c8b88d2c3"
+
+"@types/d3-request@*":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-request/-/d3-request-1.0.2.tgz#db9db8154f47816584706c6e6f702be66f22f4be"
+ dependencies:
+ "@types/d3-dsv" "*"
+
+"@types/d3-scale@*":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-1.0.11.tgz#8d92f2d07d9f225596e551d0c2f8d1459571cebf"
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-selection@*":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-1.2.0.tgz#f0a4cca0a0e4187c336c6712a82600cdcd24093f"
+
+"@types/d3-shape@*", "@types/d3-shape@^1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.2.2.tgz#f8dcdff7772a7ae37858bf04abd43848a78e590e"
+ dependencies:
+ "@types/d3-path" "*"
+
+"@types/d3-time-format@*":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-2.1.0.tgz#011e0fb7937be34a9a8f580ae1e2f2f1336a8a22"
+
+"@types/d3-time@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.7.tgz#4266d7c9be15fa81256a88d1d052d61cd8dc572c"
+
+"@types/d3-timer@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-1.0.6.tgz#786d4e20731adf03af2c5df6c86fe29667fe429b"
+
+"@types/d3-transition@*", "@types/d3-transition@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-1.1.1.tgz#c209fce6a966d6696356dd42b091a9c6cc79929f"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-voronoi@*":
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz#c0a145cf04395927e01706ff6c4ff835c97a8ece"
+
+"@types/d3-zoom@*":
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-1.7.0.tgz#1221bbf6434820f044c80b551c5519b817008961"
+ dependencies:
+ "@types/d3-interpolate" "*"
+ "@types/d3-selection" "*"
+
+"@types/d3@^4.12.0":
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/@types/d3/-/d3-4.12.0.tgz#445ede4ab7707db1a011ef43b2bd187d21bdaffc"
+ dependencies:
+ "@types/d3-array" "*"
+ "@types/d3-axis" "*"
+ "@types/d3-brush" "*"
+ "@types/d3-chord" "*"
+ "@types/d3-collection" "*"
+ "@types/d3-color" "*"
+ "@types/d3-dispatch" "*"
+ "@types/d3-drag" "*"
+ "@types/d3-dsv" "*"
+ "@types/d3-ease" "*"
+ "@types/d3-force" "*"
+ "@types/d3-format" "*"
+ "@types/d3-geo" "*"
+ "@types/d3-hierarchy" "*"
+ "@types/d3-interpolate" "*"
+ "@types/d3-path" "*"
+ "@types/d3-polygon" "*"
+ "@types/d3-quadtree" "*"
+ "@types/d3-queue" "*"
+ "@types/d3-random" "*"
+ "@types/d3-request" "*"
+ "@types/d3-scale" "*"
+ "@types/d3-selection" "*"
+ "@types/d3-shape" "*"
+ "@types/d3-time" "*"
+ "@types/d3-time-format" "*"
+ "@types/d3-timer" "*"
+ "@types/d3-transition" "*"
+ "@types/d3-voronoi" "*"
+ "@types/d3-zoom" "*"
+
+"@types/geojson@*":
+ version "7946.0.1"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.1.tgz#1fc41280e42f08f0d568401a556bc97c34f5262e"
+
"@types/jasmine@^2.0.0":
version "2.8.3"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.3.tgz#f910edc67d69393d562d10f8f3d205ea3f3306bf"
@@ -1544,12 +1751,134 @@ cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
+d3-array@^1.2.0, d3-array@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc"
+
+d3-brush@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.0.4.tgz#00c2f238019f24f6c0a194a26d41a1530ffe7bc4"
+ dependencies:
+ d3-dispatch "1"
+ d3-drag "1"
+ d3-interpolate "1"
+ d3-selection "1"
+ d3-transition "1"
+
+d3-collection@1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2"
+
+d3-color@1, d3-color@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b"
+
+d3-dispatch@1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8"
+
+d3-drag@1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.1.tgz#df8dd4c502fb490fc7462046a8ad98a5c479282d"
+ dependencies:
+ d3-dispatch "1"
+ d3-selection "1"
+
+d3-ease@1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.3.tgz#68bfbc349338a380c44d8acc4fbc3304aa2d8c0e"
+
+d3-force@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.1.0.tgz#cebf3c694f1078fcc3d4daf8e567b2fbd70d4ea3"
+ dependencies:
+ d3-collection "1"
+ d3-dispatch "1"
+ d3-quadtree "1"
+ d3-timer "1"
+
+d3-format@1, d3-format@^1.2.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.2.2.tgz#1a39c479c8a57fe5051b2e67a3bee27061a74e7a"
+
+d3-hierarchy@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz#a1c845c42f84a206bcf1c01c01098ea4ddaa7a26"
+
+d3-interpolate@1, d3-interpolate@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
+ dependencies:
+ d3-color "1"
+
+d3-path@1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764"
+
+d3-quadtree@1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.3.tgz#ac7987e3e23fe805a990f28e1b50d38fcb822438"
+
+d3-scale@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d"
+ dependencies:
+ d3-array "^1.2.0"
+ d3-collection "1"
+ d3-color "1"
+ d3-format "1"
+ d3-interpolate "1"
+ d3-time "1"
+ d3-time-format "2"
+
+d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.3.0.tgz#d53772382d3dc4f7507bfb28bcd2d6aed2a0ad6d"
+
+d3-shape@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.2.0.tgz#45d01538f064bafd05ea3d6d2cb748fd8c41f777"
+ dependencies:
+ d3-path "1"
+
+d3-time-format@2, d3-time-format@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.1.tgz#85b7cdfbc9ffca187f14d3c456ffda268081bb31"
+ dependencies:
+ d3-time "1"
+
+d3-time@1:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.8.tgz#dbd2d6007bf416fe67a76d17947b784bffea1e84"
+
+d3-timer@1:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531"
+
+d3-transition@1, d3-transition@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.1.1.tgz#d8ef89c3b848735b060e54a39b32aaebaa421039"
+ dependencies:
+ d3-color "1"
+ d3-dispatch "1"
+ d3-ease "1"
+ d3-interpolate "1"
+ d3-selection "^1.1.0"
+ d3-timer "1"
+
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
dependencies:
es5-ext "^0.10.9"
+dagre@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.7.4.tgz#de72f0e74a550ce11ce638f0a136fed712398022"
+ dependencies:
+ graphlib "^1.0.5"
+ lodash "^3.10.0"
+
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -2630,6 +2959,12 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+graphlib@^1.0.5:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-1.0.7.tgz#0cab2df0ffe6abe070b2625bfa1edb6ec967b8b1"
+ dependencies:
+ lodash "^3.10.0"
+
handle-thing@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
@@ -3630,7 +3965,7 @@ lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
-lodash@^3.8.0:
+lodash@^3.10.0, lodash@^3.8.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
diff --git a/Model/CryptoContext.cs b/Model/CryptoContext.cs
index 4ffb3ae..80e8b91 100644
--- a/Model/CryptoContext.cs
+++ b/Model/CryptoContext.cs
@@ -22,5 +22,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
public DbSet Exchanges { get; set; }
public DbSet Funds { get; set; }
public DbSet FiatBalances{ get; set; }
+ public DbSet FlowNodes { get; set; }
+ public DbSet FlowLinks { get; set; }
}
}
diff --git a/Model/DTOs/FlowLinkDTO.cs b/Model/DTOs/FlowLinkDTO.cs
new file mode 100644
index 0000000..08e3551
--- /dev/null
+++ b/Model/DTOs/FlowLinkDTO.cs
@@ -0,0 +1,14 @@
+using Model.DbModels;
+
+namespace Model.DTOs
+{
+ public class FlowLinkDTO : FlowLink
+ {
+ #region Properties
+
+ public new string FlowNodeSource { get; set; }
+ public new string FlowNodeTarget { get; set; }
+
+ #endregion
+ }
+}
diff --git a/Model/DTOs/FlowNodeDTO.cs b/Model/DTOs/FlowNodeDTO.cs
new file mode 100644
index 0000000..3fe4940
--- /dev/null
+++ b/Model/DTOs/FlowNodeDTO.cs
@@ -0,0 +1,13 @@
+using Model.DbModels;
+
+namespace Model.DTOs
+{
+ public class FlowNodeDTO : FlowNode
+ {
+ #region Properties
+
+ public new string Id { get; set; }
+
+ #endregion
+ }
+}
diff --git a/Model/DbModels/FlowLink.cs b/Model/DbModels/FlowLink.cs
new file mode 100644
index 0000000..d4b12fd
--- /dev/null
+++ b/Model/DbModels/FlowLink.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Model.DbModels
+{
+ public class FlowLink
+ {
+ public FlowLink(DateTime dateTime, decimal amount, string currency, Guid flowNodeSource, Guid flowNodeTarget, Guid exchangeId, string comment = null)
+ {
+ DateTime = dateTime;
+ Amount = amount;
+ Currency = currency;
+ FlowNodeSource = flowNodeSource;
+ FlowNodeTarget = flowNodeTarget;
+ Comment = comment;
+ ExchangeId = exchangeId;
+ Id = Guid.NewGuid();
+ }
+ public FlowLink()
+ {
+ }
+ public Guid Id { get; set; }
+ public DateTime DateTime { get; set; }
+ public decimal Amount { get; set; }
+ public string Currency { get; set; }
+ public Guid FlowNodeSource { get; set; }
+ public Guid FlowNodeTarget { get; set; }
+ public string Comment { get; set; }
+ public Guid ExchangeId { get; set; }
+ }
+}
diff --git a/Model/DbModels/FlowNode.cs b/Model/DbModels/FlowNode.cs
new file mode 100644
index 0000000..1611bb1
--- /dev/null
+++ b/Model/DbModels/FlowNode.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Model.DbModels
+{
+ public class FlowNode
+ {
+ public FlowNode()
+ {
+ }
+ public FlowNode(DateTime dateTime, decimal amount, string currency, Guid exchangeId, Guid transactionId, string comment = null)
+ {
+ DateTime = dateTime;
+ Amount = amount;
+ Currency = currency;
+ ExchangeId = exchangeId;
+ TransactionId = transactionId;
+ Comment = comment;
+ TransactionId = transactionId;
+
+ Id = Guid.NewGuid();
+ }
+
+ public Guid Id { get; set; }
+ public DateTime DateTime { get; set; }
+ public decimal Amount { get; set; }
+ public string Currency { get; set; }
+ public Guid ExchangeId { get; set; }
+ public string Comment { get; set; }
+ public Guid TransactionId { get; set; }
+ }
+}
diff --git a/Model/Migrations/20180109221301_AddFlows.Designer.cs b/Model/Migrations/20180109221301_AddFlows.Designer.cs
new file mode 100644
index 0000000..bb4961e
--- /dev/null
+++ b/Model/Migrations/20180109221301_AddFlows.Designer.cs
@@ -0,0 +1,168 @@
+//
+using CryptoManager.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.Storage.Internal;
+using Model.Enums;
+using System;
+
+namespace Model.Migrations
+{
+ [DbContext(typeof(CryptoContext))]
+ [Migration("20180109221301_AddFlows")]
+ partial class AddFlows
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125");
+
+ modelBuilder.Entity("Model.DbModels.CryptoTransaction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BuyAmount");
+
+ b.Property("BuyCurrency");
+
+ b.Property("BuyFiatAmount");
+
+ b.Property("BuyFiatRate");
+
+ b.Property("Comment");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.Property("FeeAmount");
+
+ b.Property("FeeCurrency");
+
+ b.Property("FromAddress");
+
+ b.Property("InAmount");
+
+ b.Property("InCurrency");
+
+ b.Property("OutAmount");
+
+ b.Property("OutCurrency");
+
+ b.Property("Rate");
+
+ b.Property("SellAmount");
+
+ b.Property("SellCurrency");
+
+ b.Property("ToAddress");
+
+ b.Property("TransactionHash");
+
+ b.Property("TransactionKey");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.ToTable("Transactions");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Exchange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Comment");
+
+ b.Property("ExchangeId");
+
+ b.Property("PrivateKey");
+
+ b.Property("PublicKey");
+
+ b.HasKey("Id");
+
+ b.ToTable("Exchanges");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FiatBalance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.Property("Invested");
+
+ b.Property("Payout");
+
+ b.HasKey("Id");
+
+ b.ToTable("FiatBalances");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Flow", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("DateTime");
+
+ b.Property("FlowId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("FlowId");
+
+ b.ToTable("Flows");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Fund", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.HasKey("Id");
+
+ b.ToTable("Funds");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Setting", b =>
+ {
+ b.Property("Key");
+
+ b.Property("Value");
+
+ b.HasKey("Key");
+
+ b.ToTable("Settings");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Flow", b =>
+ {
+ b.HasOne("Model.DbModels.Flow")
+ .WithMany("Parents")
+ .HasForeignKey("FlowId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Model/Migrations/20180109221301_AddFlows.cs b/Model/Migrations/20180109221301_AddFlows.cs
new file mode 100644
index 0000000..dd769ea
--- /dev/null
+++ b/Model/Migrations/20180109221301_AddFlows.cs
@@ -0,0 +1,44 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using System.Collections.Generic;
+
+namespace Model.Migrations
+{
+ public partial class AddFlows : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Flows",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Amount = table.Column(nullable: false),
+ Currency = table.Column(nullable: true),
+ DateTime = table.Column(nullable: false),
+ FlowId = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Flows", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Flows_Flows_FlowId",
+ column: x => x.FlowId,
+ principalTable: "Flows",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Flows_FlowId",
+ table: "Flows",
+ column: "FlowId");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Flows");
+ }
+ }
+}
diff --git a/Model/Migrations/20180109223036_AddFlowMeta.Designer.cs b/Model/Migrations/20180109223036_AddFlowMeta.Designer.cs
new file mode 100644
index 0000000..aa74ff3
--- /dev/null
+++ b/Model/Migrations/20180109223036_AddFlowMeta.Designer.cs
@@ -0,0 +1,172 @@
+//
+using CryptoManager.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.Storage.Internal;
+using Model.Enums;
+using System;
+
+namespace Model.Migrations
+{
+ [DbContext(typeof(CryptoContext))]
+ [Migration("20180109223036_AddFlowMeta")]
+ partial class AddFlowMeta
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125");
+
+ modelBuilder.Entity("Model.DbModels.CryptoTransaction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BuyAmount");
+
+ b.Property("BuyCurrency");
+
+ b.Property("BuyFiatAmount");
+
+ b.Property("BuyFiatRate");
+
+ b.Property("Comment");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.Property("FeeAmount");
+
+ b.Property("FeeCurrency");
+
+ b.Property("FromAddress");
+
+ b.Property("InAmount");
+
+ b.Property("InCurrency");
+
+ b.Property("OutAmount");
+
+ b.Property("OutCurrency");
+
+ b.Property("Rate");
+
+ b.Property("SellAmount");
+
+ b.Property("SellCurrency");
+
+ b.Property("ToAddress");
+
+ b.Property("TransactionHash");
+
+ b.Property("TransactionKey");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.ToTable("Transactions");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Exchange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Comment");
+
+ b.Property("ExchangeId");
+
+ b.Property("PrivateKey");
+
+ b.Property("PublicKey");
+
+ b.HasKey("Id");
+
+ b.ToTable("Exchanges");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FiatBalance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.Property("Invested");
+
+ b.Property("Payout");
+
+ b.HasKey("Id");
+
+ b.ToTable("FiatBalances");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Flow", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.Property("FlowId");
+
+ b.Property("TransactionId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("FlowId");
+
+ b.ToTable("Flows");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Fund", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.HasKey("Id");
+
+ b.ToTable("Funds");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Setting", b =>
+ {
+ b.Property("Key");
+
+ b.Property("Value");
+
+ b.HasKey("Key");
+
+ b.ToTable("Settings");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Flow", b =>
+ {
+ b.HasOne("Model.DbModels.Flow")
+ .WithMany("Parents")
+ .HasForeignKey("FlowId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Model/Migrations/20180109223036_AddFlowMeta.cs b/Model/Migrations/20180109223036_AddFlowMeta.cs
new file mode 100644
index 0000000..6f4d370
--- /dev/null
+++ b/Model/Migrations/20180109223036_AddFlowMeta.cs
@@ -0,0 +1,35 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using System.Collections.Generic;
+
+namespace Model.Migrations
+{
+ public partial class AddFlowMeta : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "ExchangeId",
+ table: "Flows",
+ nullable: false,
+ defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
+
+ migrationBuilder.AddColumn(
+ name: "TransactionId",
+ table: "Flows",
+ nullable: false,
+ defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "ExchangeId",
+ table: "Flows");
+
+ migrationBuilder.DropColumn(
+ name: "TransactionId",
+ table: "Flows");
+ }
+ }
+}
diff --git a/Model/Migrations/20180207154831_NewFlowStructure.Designer.cs b/Model/Migrations/20180207154831_NewFlowStructure.Designer.cs
new file mode 100644
index 0000000..5fd09f0
--- /dev/null
+++ b/Model/Migrations/20180207154831_NewFlowStructure.Designer.cs
@@ -0,0 +1,183 @@
+//
+using CryptoManager.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.Storage.Internal;
+using Model.Enums;
+using System;
+
+namespace Model.Migrations
+{
+ [DbContext(typeof(CryptoContext))]
+ [Migration("20180207154831_NewFlowStructure")]
+ partial class NewFlowStructure
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125");
+
+ modelBuilder.Entity("Model.DbModels.CryptoTransaction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BuyAmount");
+
+ b.Property("BuyCurrency");
+
+ b.Property("BuyFiatAmount");
+
+ b.Property("BuyFiatRate");
+
+ b.Property("Comment");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.Property("FeeAmount");
+
+ b.Property("FeeCurrency");
+
+ b.Property("FromAddress");
+
+ b.Property("InAmount");
+
+ b.Property("InCurrency");
+
+ b.Property("OutAmount");
+
+ b.Property("OutCurrency");
+
+ b.Property("Rate");
+
+ b.Property("SellAmount");
+
+ b.Property("SellCurrency");
+
+ b.Property("ToAddress");
+
+ b.Property("TransactionHash");
+
+ b.Property("TransactionKey");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.ToTable("Transactions");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Exchange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Comment");
+
+ b.Property("ExchangeId");
+
+ b.Property("Passphrase");
+
+ b.Property("PrivateKey");
+
+ b.Property("PublicKey");
+
+ b.HasKey("Id");
+
+ b.ToTable("Exchanges");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FiatBalance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.Property("Invested");
+
+ b.Property("Payout");
+
+ b.HasKey("Id");
+
+ b.ToTable("FiatBalances");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FlowLink", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("DateTime");
+
+ b.Property("FlowNodeSource");
+
+ b.Property("FlowNodeTarget");
+
+ b.HasKey("Id");
+
+ b.ToTable("FlowLinks");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FlowNode", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Comment");
+
+ b.Property("Currency");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.HasKey("Id");
+
+ b.ToTable("FlowNodes");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Fund", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Amount");
+
+ b.Property("Currency");
+
+ b.Property("ExchangeId");
+
+ b.HasKey("Id");
+
+ b.ToTable("Funds");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Setting", b =>
+ {
+ b.Property("Key");
+
+ b.Property("Value");
+
+ b.HasKey("Key");
+
+ b.ToTable("Settings");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Model/Migrations/20180207154831_NewFlowStructure.cs b/Model/Migrations/20180207154831_NewFlowStructure.cs
new file mode 100644
index 0000000..b810a27
--- /dev/null
+++ b/Model/Migrations/20180207154831_NewFlowStructure.cs
@@ -0,0 +1,84 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using System.Collections.Generic;
+
+namespace Model.Migrations
+{
+ public partial class NewFlowStructure : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Flows");
+
+ migrationBuilder.CreateTable(
+ name: "FlowLinks",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Amount = table.Column(nullable: false),
+ Currency = table.Column(nullable: true),
+ DateTime = table.Column(nullable: false),
+ FlowNodeSource = table.Column(nullable: false),
+ FlowNodeTarget = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_FlowLinks", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "FlowNodes",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Amount = table.Column(nullable: false),
+ Comment = table.Column(nullable: true),
+ Currency = table.Column(nullable: true),
+ DateTime = table.Column(nullable: false),
+ ExchangeId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_FlowNodes", x => x.Id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "FlowLinks");
+
+ migrationBuilder.DropTable(
+ name: "FlowNodes");
+
+ migrationBuilder.CreateTable(
+ name: "Flows",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Amount = table.Column(nullable: false),
+ Currency = table.Column(nullable: true),
+ DateTime = table.Column(nullable: false),
+ ExchangeId = table.Column(nullable: false),
+ FlowId = table.Column(nullable: true),
+ TransactionId = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Flows", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Flows_Flows_FlowId",
+ column: x => x.FlowId,
+ principalTable: "Flows",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Flows_FlowId",
+ table: "Flows",
+ column: "FlowId");
+ }
+ }
+}
diff --git a/Model/Migrations/20180208081649_AddTransactionIdToFlowNodes.Designer.cs b/Model/Migrations/20180208081649_AddTransactionIdToFlowNodes.Designer.cs
new file mode 100644
index 0000000..da19977
--- /dev/null
+++ b/Model/Migrations/20180208081649_AddTransactionIdToFlowNodes.Designer.cs
@@ -0,0 +1,185 @@
+//
+using CryptoManager.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.Storage.Internal;
+using Model.Enums;
+using System;
+
+namespace Model.Migrations
+{
+ [DbContext(typeof(CryptoContext))]
+ [Migration("20180208081649_AddTransactionIdToFlowNodes")]
+ partial class AddTransactionIdToFlowNodes
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.1-rtm-125");
+
+ modelBuilder.Entity("Model.DbModels.CryptoTransaction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BuyAmount");
+
+ b.Property("BuyCurrency");
+
+ b.Property("BuyFiatAmount");
+
+ b.Property("BuyFiatRate");
+
+ b.Property("Comment");
+
+ b.Property("DateTime");
+
+ b.Property("ExchangeId");
+
+ b.Property("FeeAmount");
+
+ b.Property("FeeCurrency");
+
+ b.Property("FromAddress");
+
+ b.Property("InAmount");
+
+ b.Property("InCurrency");
+
+ b.Property("OutAmount");
+
+ b.Property("OutCurrency");
+
+ b.Property("Rate");
+
+ b.Property("SellAmount");
+
+ b.Property("SellCurrency");
+
+ b.Property("ToAddress");
+
+ b.Property("TransactionHash");
+
+ b.Property("TransactionKey");
+
+ b.Property("Type");
+
+ b.HasKey("Id");
+
+ b.ToTable("Transactions");
+ });
+
+ modelBuilder.Entity("Model.DbModels.Exchange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Comment");
+
+ b.Property("ExchangeId");
+
+ b.Property("Passphrase");
+
+ b.Property("PrivateKey");
+
+ b.Property("PublicKey");
+
+ b.HasKey("Id");
+
+ b.ToTable("Exchanges");
+ });
+
+ modelBuilder.Entity("Model.DbModels.FiatBalance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property