From ba58055efe0a31f3c25f52b78a70fbfc39c6dbdc Mon Sep 17 00:00:00 2001 From: Thomas <4159106+dtslvr@users.noreply.github.com> Date: Fri, 15 Apr 2022 10:22:33 +0200 Subject: [PATCH] Refactoring --- .env | 19 ----- .../position-detail-dialog.component.ts | 11 +-- .../transactions-page.component.ts | 75 ++++++++++++++----- .../src/app/services/ics/ics.service.ts | 59 --------------- libs/common/src/lib/helper.ts | 26 +++---- 5 files changed, 75 insertions(+), 115 deletions(-) delete mode 100644 apps/client/src/app/services/ics/ics.service.ts diff --git a/.env b/.env index b5ae7ec70..e96c8b6b2 100644 --- a/.env +++ b/.env @@ -12,24 +12,5 @@ POSTGRES_PASSWORD=password ACCESS_TOKEN_SALT=GHOSTFOLIO ALPHA_VANTAGE_API_KEY= DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer -DATA_SOURCES=["GHOSTFOLIO","GOOGLE_SHEETS","YAHOO"] -ENABLE_FEATURE_BLOG=true -ENABLE_FEATURE_CUSTOM_SYMBOLS=true -ENABLE_FEATURE_FEAR_AND_GREED_INDEX=true -ENABLE_FEATURE_SOCIAL_LOGIN=true -ENABLE_FEATURE_STATISTICS=true -ENABLE_FEATURE_SUBSCRIPTION=true -ENABLE_FEATURE_SYSTEM_MESSAGE=true -GOOGLE_CLIENT_ID=43371500610-uqv0gt8h5l6v2uo69c53o0h1ssfkbbni.apps.googleusercontent.com -GOOGLE_SECRET=0bOB89maN5JA43vqXkzvuHDs -GOOGLE_SHEETS_ACCOUNT=market-data@ghostfolio-337512.iam.gserviceaccount.com -GOOGLE_SHEETS_ID=1sSAsqhtleACpj0BQIrMz48TGGCXYM5RO80SeHtz_Seg -GOOGLE_SHEETS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChsFi+CYhF3CFI\nfccrucx1ZIXY3ZEVQ2R+gIhUsoGBkxoDU/oreuFB/xTYBSvIbVsub9KpLLRFKboi\nuRRs4UWodJGUZzHxYnUN5lIFA5V6hNVCzd137QKjJM7FatSiGEM/OcNqOKNkOCUs\nZlHQIkzHXtmAAA4JrpEQzNe0qdYMcYhoWG079/CvbBVx3y/90eX8ue2C1l1fDm1J\nB3yJj3GgiClH+gMRvP6om4bp+dZJ8CYDje2fTfnlZ99MxK6rQxWu/Eou6Ws8S6sf\nMhD8nCTSlG822Fuk8RLrzxHlvCFKAFEztLtCo7v56v3iTMW5sOplQa78/T7Mlpzh\njYq7YAJlAgMBAAECggEAIselaylvQgG+OhLuMSJsD9Nx9CqC7xU6THjW+osUTvxG\nw/EANvKdej4FrIr+NkSJsNU2dhQK6fa2FoqD0YDqpDgA6bCB/neskLMasP/qmzpw\nCkjwqv+VSeUcwjv+5ag87OB+v75TrTbjjierUQ9Tvy4QsJcybdQ6WagKfU7sH2xD\n8mNV4gVEYzBbWfG29v1gIdVmxKdZbfkCFB1hcvv8ZFwNq9NBIT8tbLEFfnrD9tw1\nYiK6y/efSfZ9OZ+2kIBntI0MR9jysg7tD+sDHC9Q+O8XPzwi/x4yLdFyI8uTivYA\nq/GdvnDXmH0WfuVGP8Hs059TbW7xNaMDX3cczVu4gQKBgQDTE3K4jYFE+NgXnCjD\nXUqEuOwFtEX12isA4SvrxZzw9CM7VR3yG/i43/O6B2roX0niVHPTi/n+cy2bUPy6\nXt5pO+qR6n4OsH/BpvP2vj7RNb4OaCbVstQQGvpOrNrXc678F+LwnquHek17rbV9\nXqVLYbbNd7iZNk468ZE9GeMV5QKBgQDEGgX76j8mSDH7zfdh/IO1oWOY91NdL1uh\nOsp4vPv4dhbMIPDebSyE316Zq6JwNGbD2RW3sUSRtL21z2jGzN0aqSTRUNTzFZIr\n5CLmIrxxjsoy6YkQZOx4OL4QWulj+inzdgpDsPA++HbAeGl7SJi9/2wLiqn2BNWL\nukBsjEpygQKBgGPj9Uu/s+iXN3Tc8zGZqdVryk7cxKsX53gQGAAJUj952l6O5pAY\nirm7SpXEQuTbi5Sv0OzRdqrjiTbSuffdQ7Zbo6QQbD25a4yS3SvtVr8dhuc8hPxn\nGBLTIZgwF5UU6z/kcgLbpGOGDrs0NwqwytsE0EUmnlbrq1Qb1FctNBm9AoGAGeLB\nhXZvbZM8HdwbWrDlhfVO22NSesuEkezby0JPFIYqDjoO8Z2Bsex2ZVyVrbANHK8s\nQbpBreYo4LYHQ67JRPqs5ICCC7B+QhL0VGKjc24A3OWc9TANUvVSiYAmrM7Z+MxN\nIJBbtkRAELoUWnTDzNjJn2BnfRU4RyCH3oxKS4ECgYEAgDj5jWTpFj7jX6L2OKgU\ntWWnZwW3v9PVEKFM0UTalIEL0FA99TUwJ2dxkdSagNHftVNIOj2SbKdXK+QLgVRn\naGO85QZ2IDgiOiPfuqUfmPsnk6WsZRhRSbUzdzel/ZfgLCbpErStFfnuPDCrIz7W\nIQf4jR6u3q8L6cmnKa6e0u0=\n-----END PRIVATE KEY-----\n" -IS_DEVELOPMENT_MODE=false JWT_SECRET_KEY=123456 -#MAX_ORDERS_TO_IMPORT=20 PORT=3333 -RAKUTEN_RAPID_API_KEY=db994bceaamsh39c922e3ac79677p17da8ajsnd69256103cbd -STRIPE_PUBLIC_KEY=pk_test_0OKelyHqlD6IHLq7cVuSCYWR -STRIPE_SECRET_KEY=sk_test_uZgtp2vZNugwkfALI0LQhGn8 -WEB_AUTH_RP_ID=ghostfol.io diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts index 55efc0249..3b3cd8da6 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts @@ -211,14 +211,15 @@ export class PositionDetailDialog implements OnDestroy, OnInit { ) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((data) => { - downloadAsFile({ - content: data, - fileName: `ghostfolio-export-${this.SymbolProfile?.symbol}-${format( + downloadAsFile( + data, + `ghostfolio-export-${this.SymbolProfile?.symbol}-${format( parseISO(data.meta.date), 'yyyyMMddHHmm' )}.json`, - format: 'json' - }); + 'text/plain', + 'json' + ); }); } diff --git a/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts b/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts index 61683fd75..fcfe7b8dd 100644 --- a/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts +++ b/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts @@ -7,16 +7,15 @@ import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interf import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto'; import { PositionDetailDialog } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.component'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { IcsService } from '@ghostfolio/client/services/ics/ics.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImportTransactionsService } from '@ghostfolio/client/services/import-transactions.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { downloadAsFile } from '@ghostfolio/common/helper'; -import { User } from '@ghostfolio/common/interfaces'; +import { Export, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { DataSource, Order as OrderModel } from '@prisma/client'; +import { DataSource, Order as OrderModel, Type } from '@prisma/client'; import { format, parseISO } from 'date-fns'; -import { isArray } from 'lodash'; +import { capitalize, isArray } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -51,7 +50,6 @@ export class TransactionsPageComponent implements OnDestroy, OnInit { private dataService: DataService, private deviceService: DeviceDetectorService, private dialog: MatDialog, - private icsService: IcsService, private impersonationStorageService: ImpersonationStorageService, private importTransactionsService: ImportTransactionsService, private route: ActivatedRoute, @@ -158,14 +156,15 @@ export class TransactionsPageComponent implements OnDestroy, OnInit { delete activity.id; } - downloadAsFile({ - content: data, - fileName: `ghostfolio-export-${format( + downloadAsFile( + data, + `ghostfolio-export-${format( parseISO(data.meta.date), 'yyyyMMddHHmm' )}.json`, - format: 'json' - }); + 'text/plain', + 'json' + ); }); } @@ -174,16 +173,15 @@ export class TransactionsPageComponent implements OnDestroy, OnInit { .fetchExport(activityIds) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((data) => { - downloadAsFile({ - content: this.icsService.transformActivitiesToIcsContent( - data.activities - ), - fileName: `ghostfolio-drafts-${format( + downloadAsFile( + this.getIcsContent(data.activities), + `ghostfolio-drafts-${format( parseISO(data.meta.date), 'yyyyMMddHHmm' )}.ics`, - format: 'string' - }); + 'text/plain', + 'string' + ); }); } @@ -317,6 +315,49 @@ export class TransactionsPageComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } + private getIcsContent(aActivities: Export['activities']) { + const header = [ + 'BEGIN:VCALENDAR', + 'VERSION:2.0', + 'PRODID:-//Ghostfolio//NONSGML v1.0//EN' + ]; + const events = aActivities.map((activity) => { + return this.getEvent({ + date: parseISO(activity.date), + id: activity.id, + symbol: activity.symbol, + type: activity.type + }); + }); + const footer = ['END:VCALENDAR']; + + return [...header, ...events, ...footer].join('\n'); + } + + private getEvent({ + date, + id, + symbol, + type + }: { + date: Date; + id: string; + symbol: string; + type: Type; + }) { + const today = format(new Date(), 'yyyyMMdd'); + + return [ + 'BEGIN:VEVENT', + `UID:${id}`, + `DTSTAMP:${today}T000000`, + `DTSTART;VALUE=DATE:${format(date, 'yyyyMMdd')}`, + `DTEND;VALUE=DATE:${format(date, 'yyyyMMdd')}`, + `SUMMARY:${capitalize(type)} ${symbol}`, + 'END:VEVENT' + ].join('\n'); + } + private handleImportError({ activities, error diff --git a/apps/client/src/app/services/ics/ics.service.ts b/apps/client/src/app/services/ics/ics.service.ts deleted file mode 100644 index 7329ea663..000000000 --- a/apps/client/src/app/services/ics/ics.service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Injectable } from '@angular/core'; -import { capitalize } from '@ghostfolio/common/helper'; -import { Export } from '@ghostfolio/common/interfaces'; -import { Type } from '@prisma/client'; -import { format, parseISO } from 'date-fns'; - -@Injectable({ - providedIn: 'root' -}) -export class IcsService { - private readonly ICS_DATE_FORMAT = 'yyyyMMdd'; - - public constructor() {} - - public transformActivitiesToIcsContent( - aActivities: Export['activities'] - ): string { - const header = [ - 'BEGIN:VCALENDAR', - 'VERSION:2.0', - 'PRODID:-//Ghostfolio//NONSGML v1.0//EN' - ]; - const events = aActivities.map((activity) => { - return this.getEvent({ - date: parseISO(activity.date), - id: activity.id, - symbol: activity.symbol, - type: activity.type - }); - }); - const footer = ['END:VCALENDAR']; - - return [...header, ...events, ...footer].join('\n'); - } - - private getEvent({ - date, - id, - symbol, - type - }: { - date: Date; - id: string; - symbol: string; - type: Type; - }) { - const today = format(new Date(), this.ICS_DATE_FORMAT); - - return [ - 'BEGIN:VEVENT', - `UID:${id}`, - `DTSTAMP:${today}T000000`, - `DTSTART;VALUE=DATE:${format(date, this.ICS_DATE_FORMAT)}`, - `DTEND;VALUE=DATE:${format(date, this.ICS_DATE_FORMAT)}`, - `SUMMARY:${capitalize(type)} ${symbol}`, - 'END:VEVENT' - ].join('\n'); - } -} diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index ad47abfdd..9406b4df2 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -12,28 +12,24 @@ export function decodeDataSource(encodedDataSource: string) { return Buffer.from(encodedDataSource, 'hex').toString(); } -export function downloadAsFile({ - content, - contentType = 'text/plain', - fileName, - format -}: { - content: unknown; - contentType?: string; - fileName: string; - format: 'json' | 'string'; -}) { +export function downloadAsFile( + aContent: unknown, + aFileName: string, + aContentType: string, + aType: 'json' | 'string' +) { const a = document.createElement('a'); + let content = aContent; - if (format === 'json') { - content = JSON.stringify(content, undefined, ' '); + if (aType === 'json') { + content = JSON.stringify(aContent, undefined, ' '); } const file = new Blob([content], { - type: contentType + type: aContentType }); a.href = URL.createObjectURL(file); - a.download = fileName; + a.download = aFileName; a.click(); }